Compare commits

...

235 Commits

Author SHA1 Message Date
github-actions[bot] 9d70c9ad78 Bump version to 2025.9.1-alpha.0 2025-09-19 13:51:21 +00:00
tamaina 42b2aea533 feat(frontend): 自分のプロフィールページの二次元コード(QRコード)を表示し、他の人のコードを読み取りするページを追加 (#16456)
* wip (qr.show.vue)

* added to navbar

* qr.show.vue

* fix

* added to navbar

* fix size

* 🎨

* 🎨

* fix div warn

* fix

* use * 0.25

* fix??

* fix lint

* clean up

* ???

* ?

* fix

* 🎨

* 🎨

* refactor

* 🎨

* 🎨

* :ar:t

* 🎨

* iphone flip

* no lazy import

* 🎨

* 🎨

* 🎨

* ユーザー全部flipでいいや

* ✌️

* fix

* fix

* fix lint

* 🎨

* fix type

* fix: local user profile url cannot be resolved with ap/show

* fix: local user url with hostname could not be resolved

* chore: use common utility for checking self host

* wip

* 🎨

* 🎨

* fix imports

* fix

* fix

* fix

* 🎨

* fix...

* set spacer-w

* ✌️

* 全画面でQRを読むように

* fix

* 🎨

* modify navbar.ts

* start/stop on vue activation

* display raw content read from qr

* 端末のQRをスキャンするボタンを追加

* chore

* やっぱりmfmを先に表示する

* 🎨

* fix 18n

* QRの内容は/users/:userIdにする

* add spdx

* use cqh

* `defineProps` is a compiler macro and no longer needs to be imported.

* use MkUserName

* 🎨

* 🎨

* refactor

* clean up

* refactor

* 🎨

* Update qr.show.vue

* Misskeyロゴにdrop-shadowを追加

* clean up: do not use empty css

* fix os.select usage

* Update qr.vue

* Update qr.show.vue

* Update qr.show.vue

* Update get-user-menu.ts

* ✌️

* Update show.ts

* Update ja-JP.yml

* watermark

* Update CHANGELOG.md

* Update qr.read.vue

* Update qr.read.vue

* wip

* Update MkWatermarkEditorDialog.Layer.vue

---------

Co-authored-by: anatawa12 <anatawa12@icloud.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-09-19 21:02:30 +09:00
syuilo 97adf6f2cc 🎨 2025-09-19 14:23:34 +09:00
tamaina 93ff209c51 enhance(frontend): bootでonunhandledrejectionでrenderErrorする場合、PromiseRejectionEvent.reasonを渡すように (#16563) 2025-09-18 19:35:23 +09:00
syuilo 5fe08d0bbb fix(frontend): iOSで、デバイスがダークモードだと初回読み込み時にエラーになる問題を修正
Fix #16562
2025-09-18 19:18:31 +09:00
syuilo 8c413d01e6 enhance(frontend): マスクエフェクト (#16556)
* wip

* wip

* Update MkImageEffectorDialog.vue

* Update MkImageEffectorDialog.vue

* Update MkImageEffectorDialog.vue

* Update MkImageEffectorDialog.vue

* Update MkImageEffectorDialog.vue

* Update fillSquare.ts

* Update CHANGELOG.md

* Update fillSquare.ts
2025-09-17 18:38:56 +09:00
syuilo b231da7c7c enhance(frontend): チャットの日本語名称をダイレクトメッセージに & ベータを外す 2025-09-16 16:24:10 +09:00
syuilo df3e44f62e enhance(backend): allow upload csv by default
Related #16541
2025-09-16 12:16:18 +09:00
かっこかり e504560477 fix: サーバー設定によりコンテンツの閲覧が制限されている場合のメッセージを区別するように (#16527) 2025-09-16 11:53:20 +09:00
syuilo bcb2073715 enhance(backend): 初期設定をスキップした場合の初期状態ポリシーでインポート系をオプトインに
Resolve #16540
2025-09-16 11:26:35 +09:00
syuilo 6a80c23a50 chore(frontend): enable enableFolderPageView by default 2025-09-15 14:33:32 +09:00
syuilo 2621f468ff enhance: 広告ごとにセンシティブフラグを設定できるように 2025-09-14 15:25:22 +09:00
かっこかり d4654dd7bd refactor(frontend): os.select, MkSelectのitem指定をオブジェクトによる定義に統一し、型を狭める (#16475)
* refactor(frontend): MkSelectのitem指定をオブジェクトによる定義に統一

* fix

* spdx

* fix

* fix os.select

* fix lint

* add comment

* fix

* fix: os.select対応漏れを修正

* fix

* fix

* fix: MkSelectのmodelに対する型チェックを厳格化

* fix

* fix

* fix

* Update packages/frontend/src/components/MkEmbedCodeGenDialog.vue

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>

* fix

* fix types

* fix

* fix

* Update packages/frontend/src/pages/admin/roles.editor.vue

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>

* fix: MkSelectに直接配列を指定している場合に正常に型が解決されるように

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-09-13 21:00:33 +09:00
renovate[bot] b7da6cad87 fix(deps): update dependency vite [security] (#16535)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-13 10:32:49 +09:00
かっこかり 5b4115e21a refactor(frontend): フロントエンドの型エラー解消(途中まで) (#16539)
* fix(frontend): FormLinkをボタンとして使用した際にエラーが出る問題を修正

* refactor(frontend): フロントエンドの型エラー解消

* remove unused ts-expect-error

* migrate

* remove unrelated changes

* fix lint

* more type fixes
2025-09-13 08:33:14 +09:00
syuilo c174c5c144 Update CHANGELOG.md 2025-09-12 17:13:13 +09:00
かっこかり aebc3f781e perf(frontend): 低精度な現在時刻を一か所で管理するように (#16479)
* perf(frontend): 低精度な現在時刻を一か所で管理するように

* lint

* fix

* remove unused imports

* fix

* Update Changelog

* [ci skip] typo

* enhance: カレンダーウィジェットの日付変更は時間通りに行うように

* [ci skip] fix
2025-09-12 17:12:50 +09:00
かっこかり f60b6291d7 chore(gh): add frontend-builder to renovate 2025-09-10 10:01:25 +09:00
taiy 7673874675 fix(eslint): add window prefix rules to frontend-embed & frontend-shared (#16531) 2025-09-10 09:22:12 +09:00
github-actions[bot] 6e3354f95d [skip ci] Update CHANGELOG.md (prepend template) 2025-09-08 12:29:30 +00:00
github-actions[bot] b9df928097 Release: 2025.9.0 2025-09-08 12:29:25 +00:00
github-actions[bot] 0754678144 Bump version to 2025.9.0-rc.0 2025-09-08 11:33:58 +00:00
tamaina a8cc51dc77 fix(frontend): Safari 26でモバイルUIが崩れる問題に対するhotfix (#16528) 2025-09-08 20:32:19 +09:00
github-actions[bot] 690edcef16 Bump version to 2025.9.0-beta.1 2025-09-08 11:21:12 +00:00
renovate[bot] 2ea784f345 fix(deps): update [backend] update dependencies (#16491)
* fix(deps): update [backend] update dependencies

* fix type error

* run pnpm dedupe

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-09-08 17:11:18 +09:00
renovate[bot] 20d257b562 chore(deps): update [misskey-js] update dependencies (#16489)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-08 16:14:23 +09:00
renovate[bot] c215415613 fix(deps): update [root] update dependencies (#16490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-08 16:08:15 +09:00
github-actions[bot] 726c03d96a Bump version to 2025.9.0-beta.0 2025-09-08 06:32:15 +00:00
syuilo e65ddb546c New Crowdin updates (#16526)
* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Russian)
2025-09-08 15:20:07 +09:00
renovate[bot] 85aea9077f fix(deps): update [frontend] update dependencies (#16492)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-08 15:16:22 +09:00
syuilo f3fffce6a9 fix type 2025-09-08 14:57:53 +09:00
syuilo eb7db5a3aa Update MkSuspense.vue 2025-09-08 14:56:58 +09:00
syuilo e33eb26863 Update CHANGELOG.md 2025-09-07 19:41:40 +09:00
かっこかり 430310f306 fix(frontend): ctrlキーを押しながらリンクをクリックしても新しいタブで開かない問題を修正 (#16453)
* fix(frontend): ctrlキーを押しながらクリックしても新しいタブで開かない問題を修正

* Update Changelog

* fix: 制御キーの場合を個別ハンドリングするのではなくブラウザ既定の挙動に任せるように

* fix
2025-09-07 09:32:32 +09:00
syuilo 1e1eea521e chore(frontend): add force cloud backup button for debugging 2025-09-07 09:16:25 +09:00
syuilo 86ad771221 New Crowdin updates (#16525)
* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Russian)
2025-09-07 09:01:12 +09:00
syuilo 057acf471e New Crowdin updates (#16493)
* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Spanish)
2025-09-06 20:53:36 +09:00
github-actions[bot] 2bfe257879 Bump version to 2025.9.0-alpha.2 2025-09-06 08:54:34 +00:00
syuilo 6d75624aa8 Update CHANGELOG.md 2025-09-06 17:49:53 +09:00
tamaina 369f0ec88a fix(backend): webpなどの画像に対してセンシティブなメディアの検出が適用されていなかった問題を修正 (#16523)
画像をnsfwjsにかける前にsharpで均一にするようにした
2025-09-06 17:48:53 +09:00
かっこかり 788c5660ba enhance(frontend): フロントエンドのキャッシュクリア操作でブラウザの内部キャッシュも削除するように (#16522)
* enhance(frontend): フロントエンドのキャッシュクリア操作でブラウザの内部キャッシュも削除するように

* 削除するキャッシュを増やす

* Update Changelog

* fix: 何らかのエラーがあっても無視するように
2025-09-06 14:46:24 +09:00
github-actions[bot] 6cf1f86636 Bump version to 2025.9.0-alpha.1 2025-09-06 03:42:29 +00:00
syuilo 5b994b3e03 fix(frontend): プロファイルを復元後アカウントの切り替えができない問題を修正
Fix #16508
2025-09-06 12:41:27 +09:00
syuilo 7b2abb7577 enhance(frontend): クリップ/リスト/アンテナ/ロール追加系メニュー項目において、表示件数を拡張
#16510
2025-09-06 11:18:08 +09:00
github-actions[bot] b681788315 Bump version to 2025.9.0-alpha.0 2025-09-06 02:11:36 +00:00
syuilo 279af1d72f Update CHANGELOG.md 2025-09-06 11:10:41 +09:00
syuilo 9e188ca3fa Revert "refactor"
This reverts commit aa85d701b9.
2025-09-06 11:09:24 +09:00
syuilo de1b2223ff enhance(frontend): AiScriptAppウィジェットで構文エラーを検知してもダイアログではなくウィジェット内にエラーを表示するように 2025-09-05 19:44:11 +09:00
なっかあ 9b565728e7 fix #16494 (#16509) 2025-09-05 15:26:39 +09:00
饺子w (Yumechi) a92fd8856a feat(backend): Send Clear-Site-Data header on /flush (#16517)
* feat(backend): Send Clear-Site-Data header on /flush

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* simplify check on flush.pug

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

---------

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
2025-09-05 13:55:37 +09:00
takaion 047773341d fix(frontend): エラー画像が横に引き伸ばされてしまう問題に対応 (#16502)
* fix(frontend): エラー画像が横に引き伸ばされてしまう問題に対応

Fix misskey-dev#15982

* Update CHANGELOG.md
2025-09-02 16:40:57 +09:00
yukineko 842670e100 fix(frontend): RSSティッカーウィジェットが正しく動作しない問題を修正 (#16498)
* fix: RSSティッカーウィジェットが正しく機能しない問題を修正

* chore: update CHANGELOG.md
2025-09-02 10:29:25 +09:00
anatawa12 ffc481a994 fix: 「自動でもっと見る」の設定ができない問題 (#16500) 2025-09-02 10:11:50 +09:00
syuilo 2ccf4f94cb refactor 2025-09-01 16:51:58 +09:00
syuilo 3566bc207f refactor 2025-09-01 16:36:15 +09:00
syuilo 4a0e968662 refactor 2025-09-01 16:23:05 +09:00
syuilo b1479ab1d8 Update misskey-js.api.md 2025-09-01 14:07:24 +09:00
syuilo 18a9ccf7af pnpm dedupe 2025-09-01 14:07:14 +09:00
syuilo 959e72b2b3 refactor 2025-09-01 14:02:14 +09:00
syuilo a3d78b2f08 refactor 2025-09-01 13:41:40 +09:00
syuilo 3c998e1f48 refactor 2025-09-01 12:59:53 +09:00
syuilo 782c9f9852 refactor 2025-09-01 12:33:44 +09:00
syuilo d27c740ab0 refactor 2025-09-01 12:31:27 +09:00
syuilo 08ecf7ca79 refactor 2025-09-01 10:19:14 +09:00
syuilo bdec4bf87a refactor 2025-09-01 10:16:33 +09:00
syuilo 7000095b44 refactor 2025-09-01 10:01:03 +09:00
syuilo 18e42cc83d refactoe 2025-09-01 09:53:38 +09:00
syuilo 11204eeb43 refactor 2025-09-01 09:50:36 +09:00
かっこかり c95092903a refactor(frontend): フロントエンドの型エラー解消(途中まで) (#16477)
* refactor(frontend): フロントエンドの型エラー解消

* fix

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-08-31 19:53:38 +09:00
github-actions[bot] 21b2b9e5f8 [skip ci] Update CHANGELOG.md (prepend template) 2025-08-31 08:42:45 +00:00
github-actions[bot] 665ec2c43c Release: 2025.8.0 2025-08-31 08:42:39 +00:00
syuilo 34bd840525 Update CHANGELOG.md 2025-08-31 15:56:07 +09:00
syuilo 3d1cbcf094 Update CHANGELOG.md 2025-08-31 15:29:22 +09:00
github-actions[bot] 5f5d88036f Bump version to 2025.8.0-rc.0 2025-08-31 01:32:06 +00:00
syuilo 24739cd040 New Crowdin updates (#16483)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Italian)
2025-08-31 10:24:41 +09:00
syuilo b491432daa fix(frontend): タッチ操作時にマウスホバー時のユーザープレビューが開くことがある問題を修正
Fix #16464
2025-08-31 10:23:29 +09:00
syuilo ebe029458e enhance(frontend): アイコンのスクロール追従を無効化する際の適用範囲を強化
Resolve #16485
2025-08-31 10:18:48 +09:00
syuilo d127d82c5b Update CHANGELOG.md 2025-08-30 19:17:11 +09:00
syuilo aabda5a956 clean up 2025-08-30 19:15:52 +09:00
syuilo bd5b38c9d9 Update CHANGELOG.md 2025-08-30 19:12:53 +09:00
syuilo 647e03bf34 update locale 2025-08-30 19:10:19 +09:00
syuilo d16db7f311 New translations ja-jp.yml (English) (#16472) 2025-08-30 16:11:27 +09:00
github-actions[bot] ec4731dee4 Bump version to 2025.8.0-beta.6 2025-08-29 07:38:45 +00:00
syuilo 65a4d77a7f fix(backend): タイムラインAPIの withRenotes: false 時のレスポンスを修正 2025-08-29 16:03:03 +09:00
かっこかり 328301ffc2 fix(misskey-js): run api extractor (#16476) 2025-08-29 13:37:17 +09:00
syuilo def148d7a6 refactor 2025-08-28 20:02:28 +09:00
syuilo aa85d701b9 refactor 2025-08-28 19:53:10 +09:00
syuilo f0833cffe9 refactor 2025-08-28 19:47:58 +09:00
github-actions[bot] 9cd918f12b Bump version to 2025.8.0-beta.5 2025-08-28 05:33:23 +00:00
syuilo 195a80622b New Crowdin updates (#16457)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (English)
2025-08-28 13:31:05 +09:00
syuilo 8b347e23e3 refactor 2025-08-28 13:30:52 +09:00
syuilo bca3602da2 refactor 2025-08-28 13:24:25 +09:00
syuilo cfd4d7c57b refactor 2025-08-28 13:20:11 +09:00
tamaina 084ccf5c9a build-misskey-js-with-types (#16471)
* build-misskey-js-with-types

* build-misskey-js-with-types
2025-08-28 11:45:46 +09:00
syuilo fc1693f768 そもそもnullになることはあり得なかった 2025-08-28 11:39:54 +09:00
syuilo ff6f115976 refactor 2025-08-28 11:30:03 +09:00
syuilo 8c2b96ad37 lint 2025-08-28 11:16:40 +09:00
syuilo 3e24419981 refactor 2025-08-28 11:15:17 +09:00
tamaina 25c2007f59 build-misskey-js-with-types (#16470) 2025-08-28 10:39:39 +09:00
syuilo 2e4c4dd555 refactor 2025-08-28 08:59:13 +09:00
taiy 653cb116ea fix(build): run build-misskey-js-with-types (#16468) 2025-08-27 19:11:05 +09:00
syuilo c9f363b215 fix i/apps schema 2025-08-27 17:21:24 +09:00
syuilo e72da587e4 型の漏れを修正 2025-08-27 17:05:29 +09:00
syuilo 439337a108 json schemaに誤りがあるのを修正 2025-08-27 17:01:02 +09:00
syuilo 5fef2332f4 refactor 2025-08-27 17:00:58 +09:00
syuilo 40a325cbe7 userのjson schemaに誤りがあるのを修正 2025-08-27 16:55:07 +09:00
syuilo 5eff31383f refactor 2025-08-27 16:52:58 +09:00
syuilo 575379a683 refactor 2025-08-27 16:48:32 +09:00
syuilo bf82b49633 refactor 2025-08-27 16:27:16 +09:00
syuilo 87d09f255d refactor 2025-08-27 15:59:39 +09:00
syuilo 98e07c3bd1 perf(frontend): use WeakMap 2025-08-27 12:41:24 +09:00
syuilo c5bb881438 refactor 2025-08-27 12:40:11 +09:00
syuilo ee96f77ef2 refactor 2025-08-27 12:09:19 +09:00
syuilo 55eb18f5a6 Update CHANGELOG.md 2025-08-27 10:29:45 +09:00
syuilo aa8daca914 chore(frontend): skip typecheck for auto-generated files 2025-08-27 10:23:41 +09:00
syuilo 3e9118af3d fix(frontend): lookupページでリモートURLを指定した際に正しく動作しない問題を修正 2025-08-27 10:15:11 +09:00
syuilo 25df56dfd0 refactor 2025-08-27 10:14:17 +09:00
syuilo 231ccae006 tweak locale 2025-08-27 09:57:33 +09:00
syuilo 2e0a34300a refactor 2025-08-27 09:46:31 +09:00
syuilo d2fd7460ed Update CHANGELOG.md
#16465
2025-08-27 00:41:11 +09:00
syuilo 5e3d8fc9b8 refactor 2025-08-26 20:17:25 +09:00
syuilo b186c67767 refactor 2025-08-26 20:04:59 +09:00
syuilo ac7c60d102 refactor and fix 2025-08-26 19:06:15 +09:00
syuilo b9dbd58a1c refactor 2025-08-26 18:54:54 +09:00
syuilo 69bbac013a refactor 2025-08-26 17:31:36 +09:00
syuilo 203296b9cb chore(frontend): tweak MkServerSetupWizard 2025-08-26 15:02:12 +09:00
syuilo 689d70ffae refactor 2025-08-26 14:38:42 +09:00
syuilo d5475d1ff6 refactor 2025-08-26 14:22:53 +09:00
syuilo 05cc8047fa refactor 2025-08-26 13:58:57 +09:00
syuilo d6a1046361 refactor 2025-08-26 13:34:41 +09:00
syuilo eb9915baf8 refactor and fix 2025-08-26 10:56:09 +09:00
syuilo dbb6c71c5c refactor 2025-08-26 09:39:23 +09:00
syuilo 9e5c8d94bf refactor 2025-08-26 09:08:00 +09:00
syuilo 120af977a9 refactoe 2025-08-26 08:57:36 +09:00
syuilo 506c8a259b refactor 2025-08-26 08:50:34 +09:00
syuilo 0c8545ec1c Update CHANGELOG.md 2025-08-26 07:44:26 +09:00
tamaina 7e7dc03796 fix(frontend): ap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正 (#16460) 2025-08-26 07:43:59 +09:00
syuilo a874def344 remove unused file 2025-08-25 20:32:07 +09:00
syuilo 44ac51f64f refactor: ReloadSuggest -> ReloadSuggestion 2025-08-25 20:31:22 +09:00
syuilo 3b65be8b91 clean up 2025-08-25 20:29:26 +09:00
syuilo 76beac41d2 refactor 2025-08-25 20:07:33 +09:00
syuilo 69cdc73f5a refactor 2025-08-25 19:55:42 +09:00
syuilo 1c966db324 refactor 2025-08-25 17:12:11 +09:00
syuilo 692284886b refactor 2025-08-25 17:04:49 +09:00
syuilo 0121d19645 refactor 2025-08-25 16:56:10 +09:00
syuilo bf8636e516 refactor 2025-08-25 16:56:05 +09:00
syuilo d336a1fb1c refactor 2025-08-25 13:51:52 +09:00
syuilo 7c761e7017 refactor 2025-08-25 13:48:09 +09:00
syuilo 7924daf7f8 refactor 2025-08-25 13:46:22 +09:00
syuilo 2b9706a68b refactor 2025-08-25 13:40:41 +09:00
syuilo f2d15f9240 refactor 2025-08-25 13:36:38 +09:00
syuilo caf6a3ab81 refactor 2025-08-25 13:34:17 +09:00
syuilo f4baa973bf refactor 2025-08-25 13:26:41 +09:00
syuilo 3741fa4b49 refactor 2025-08-25 13:25:05 +09:00
syuilo 27df7f643e fix typo
Fix #16452
2025-08-25 10:07:42 +09:00
syuilo 30987b6f1f Update CHANGELOG.md 2025-08-25 10:05:15 +09:00
anatawa12 41b5677f01 fix: Pages will be deleted when eye-catching image is moved (#16455) 2025-08-25 10:04:35 +09:00
github-actions[bot] 47d83e8930 Bump version to 2025.8.0-beta.4 2025-08-24 09:29:08 +00:00
renovate[bot] 61ff1f313b fix(deps): update [backend] update dependencies (#16450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 18:27:14 +09:00
renovate[bot] 637ad3d479 chore(deps): update [misskey-js] update dependencies (#16448)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 16:05:06 +09:00
syuilo 2dd8c2a355 New Crowdin updates (#16442)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Turkish)
2025-08-24 12:02:36 +09:00
renovate[bot] 857a87d4b6 chore(deps): update [github actions] update dependencies (#16447)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 11:53:23 +09:00
renovate[bot] 8b4cea5c86 fix(deps): update [root] update dependencies (#16449)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 11:53:10 +09:00
renovate[bot] 9f25d96ec3 fix(deps): update [frontend] update dependencies (#16387)
* fix(deps): update [frontend] update dependencies

* fix build error

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-08-24 09:13:04 +09:00
syuilo bd0730e5e8 fix(backend): 削除されたユーザーがチャットメッセージにリアクションしている場合chat/historyなどでエラーになる問題を修正
Fix #16445
2025-08-23 17:37:15 +09:00
syuilo 07ccb82691 Update CHANGELOG with recent feature and fix entries 2025-08-22 19:40:15 +09:00
github-actions[bot] 16030c6381 Bump version to 2025.8.0-beta.3 2025-08-22 10:39:14 +00:00
syuilo 1f6716d69b New Crowdin updates (#16436)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Italian)
2025-08-22 19:37:20 +09:00
かっこかり ade603ff7a fix(frontend): ページネーションの進行方向を指定できるように (#16433)
* fix(frontend): ページネーションの進行方向を指定できるように

* Update Changelog

* fix lint

* fix: directionをMkPaginationに移動

* fix

* fix

* fix

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-08-22 19:34:20 +09:00
かっこかり 4d215bde10 fix(frontend): follow-up of #16380 2025-08-22 19:31:27 +09:00
かっこかり 20d81696e1 fix(backend): fix test (#16441)
* fix(backend): fix test

* fix

* fix
2025-08-22 18:26:19 +09:00
syuilo 8cbbb80e3f fix(backend): notes/mentions で場合によっては並び順が正しく返されない問題を修正
Fix #16398
2025-08-21 19:10:16 +09:00
かっこかり 1eabb21d69 fix(backend): クリップ一覧APIをページネーションに対応させる (#16434)
* fix(backend): クリップ一覧APIをページネーションに対応させる

* Update Changelog
2025-08-21 19:02:21 +09:00
かっこかり 7f6ba2e501 enhance: verify-emailにフロントエンドUIを実装 (#16431)
* enhance: メールのverifyをAPIに変更

* enhance(frontend): メールのVerifyページを追加

* fix

* 🎨

* 🎨

* Update Changelog

* lint
2025-08-21 16:52:30 +09:00
github-actions[bot] 8c433d2706 Bump version to 2025.8.0-beta.2 2025-08-20 07:41:12 +00:00
syuilo 3a856b785d New Crowdin updates (#16416)
* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)
2025-08-20 16:35:50 +09:00
syuilo b07bf838e3 サーバー管理コマンド (#15882)
* wip

* Update cli.ts

* Update cli.ts

* wip

* Update CHANGELOG.md

* Delete cli.mjs
2025-08-20 16:35:26 +09:00
syuilo bdfe709319 fix(frontend): 読み込み直後にプラグインによるノートの書き換えが行われない問題を修正
ブート時にプラグインがロードされるまで待機
Fix #16428
2025-08-20 15:57:20 +09:00
github-actions[bot] 4190c6cb8e Bump version to 2025.8.0-beta.1 2025-08-19 05:24:14 +00:00
renovate[bot] 44a2d531b3 fix(deps): update dependency tmp to v0.2.4 [security] (#16374)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 14:20:53 +09:00
syuilo a17271a5c4 Update CHANGELOG.md 2025-08-19 14:19:54 +09:00
syuilo 3980172243 feat: 非ログイン時に表示されるトップページのスタイルを選択できるように 2025-08-19 14:15:19 +09:00
syuilo 3b4879133c 🎨 2025-08-18 18:06:32 +09:00
syuilo a1232cbae3 Update CHANGELOG.md 2025-08-18 14:47:35 +09:00
github-actions[bot] ebb014da4c Bump version to 2025.8.0-beta.0 2025-08-18 05:41:44 +00:00
syuilo 7786761d76 chore(frontend): more haptic 2025-08-18 14:24:14 +09:00
Souma ff334fe9d7 enhance(frontend): Add an option to customize Lockdown duration (#16405)
* chore(locales): Add "setManually" and "_time.month"

Add Japanese locales to auto-generate other languages.

* feat(frontend): Add text fields to set lockdown duration manually

Choose from presets or set it manually.

* refactor(frontend): Make objects contains option's values and labels

When adding a new option, it needed to write two times.

* docs(changelog): Add a description about this change

Users can notice what's changed by this PR.

* refactor(frontend): Manage state by MkSelect

The functions only initialize the values.

* refactor(frontend): Make the custom input as writable computed

Clean up the MkInput components.

* chore(locales): Switch to "custom"

A single word is better than sentence on this situation.

* refactor(frontend): Insert the custom button to presets

Users don't need to click multiple times to use prests.
2025-08-18 14:11:48 +09:00
syuilo ba40cb750b Update about-misskey.vue 2025-08-18 10:59:31 +09:00
syuilo fcde6789ff feat(frontend): introduce haptic feedback as experimental feature
#16410
2025-08-18 10:49:27 +09:00
github-actions[bot] 14cc42e305 Bump version to 2025.8.0-alpha.13 2025-08-18 01:22:39 +00:00
syuilo e481205342 enhance(frontend): update aiscript to 1.1.0 2025-08-18 10:18:34 +09:00
anatawa12 fea9f27fd6 chore: preserve notes with local reactions (#16412) 2025-08-17 17:08:38 +09:00
github-actions[bot] 9ea7340da6 Bump version to 2025.8.0-alpha.12 2025-08-15 13:44:57 +00:00
anatawa12 60f7278aff fix: Remote Note Cleaning will delete notes embedded in a page (#16408)
* feat: preserve number of pages referencing the note

* chore: delete pages on account delete

* fix: notes on the pages are removed by CleanRemoteNotes

* test: add the simplest test for page embedded notes

* fix: section block is not considered

* fix: section block is not considered in migration

* chore: remove comments from columns

* revert unnecessary change

* add pageCount to webhook test

* fix type error on backend
2025-08-15 22:39:55 +09:00
syuilo bae92a944d enhance(frontend): improve enableInfiniteScroll stability
Close #16318
2025-08-15 12:40:37 +09:00
syuilo 7d30768769 fix(frontend): Botプロテクションの設定の変更検知が正しくない問題を修正 2025-08-15 12:10:14 +09:00
github-actions[bot] e444942c4e Bump version to 2025.8.0-alpha.11 2025-08-14 08:02:14 +00:00
饺子w (Yumechi) 90b9609341 enhance: performance for CleanRemoteNotesProcessorService (#16404)
* enhance: performance for CleanRemoteNotesProcessorService

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* suggestions

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* docs

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* change initial limit to 100

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* robustness for transient race conditions

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* handle cursors in postgres

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* robustness: transient errors and timeout handling

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* use '0' as initial cursor

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

---------

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
2025-08-14 16:54:28 +09:00
syuilo c25a922928 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-08-14 16:50:59 +09:00
syuilo d26169ea32 Update about-misskey.vue 2025-08-14 16:50:56 +09:00
github-actions[bot] 8839d8d679 Bump version to 2025.8.0-alpha.10 2025-08-13 02:01:57 +00:00
syuilo ad6af74eef New Crowdin updates (#16394)
* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Chinese Simplified)
2025-08-13 10:59:40 +09:00
Sayamame-beans 7bb43329bb fix(frontend): メンション補完のためのサジェストが正しく表示されない問題を修正 (#16401)
* fix(frontend): mention-syntax detection for autocomplete doesn't work properly

* docs(changelog): update changelog
2025-08-13 10:51:23 +09:00
syuilo 4c41930554 Update CHANGELOG.md 2025-08-11 15:54:18 +09:00
syuilo 295f42b986 New Crowdin updates (#16386)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Norwegian)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Slovak)

* New translations ja-jp.yml (Swedish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Ukrainian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Bengali)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Uzbek)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Italian)
2025-08-11 12:25:59 +09:00
syuilo 299f9e3115 fix test 2025-08-11 12:09:25 +09:00
syuilo 1d8e183883 fix test 2025-08-11 12:01:32 +09:00
zyoshoka f242892382 fix(workflow): correct references to built image's ID (#16391) 2025-08-10 23:54:06 +09:00
syuilo ecc033f101 fix(backend): fix type errors caused by dependency update
https: //github.com/misskey-dev/misskey/pull/16308
Co-Authored-By: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-08-09 17:41:01 +09:00
renovate[bot] 684dbfd626 fix(deps): update [backend] update dependencies (#16201)
* fix(deps): update [backend] update dependencies

* Update HttpRequestService.ts

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-08-09 17:00:59 +09:00
github-actions[bot] aa5c42997f Bump version to 2025.8.0-alpha.9 2025-08-09 07:45:10 +00:00
github-actions[bot] e7b666f567 Bump version to 2025.8.0-alpha.8 2025-08-09 06:04:17 +00:00
renovate[bot] 0f7c0ed053 chore(deps): update [misskey-js] update dependencies (#16346)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-09 14:48:02 +09:00
syuilo 1e92bb4a0a chore(backend): remove unused codes 2025-08-09 14:44:36 +09:00
かっこかり b5b7914073 enhance: ユーザー検索を制限できるように (#16380)
* enhance: ユーザー検索を制限できるように

* Update Changelog
2025-08-09 14:41:11 +09:00
syuilo 7595bff43b fix(backend): prevent run repeatable job immediately
Fix #16357
2025-08-09 14:37:09 +09:00
github-actions[bot] 72864fcbd0 Bump version to 2025.8.0-alpha.7 2025-08-09 05:27:57 +00:00
syuilo 1b0de39f92 Update CHANGELOG.md 2025-08-09 14:27:48 +09:00
renovate[bot] d8a137cb6c chore(deps): update [tools] update dependencies (#16348)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-09 14:26:52 +09:00
かっこかり ddac2fb7a1 fix(frontend-builder): 言語バンドルの作成状況がログに残るように (#16385) 2025-08-09 14:26:03 +09:00
かっこかり b1b335d55a fix: チャットの利用可否ポリシーの考慮漏れを修正 (#16259)
* fix: チャットの利用可否ポリシーの考慮漏れを修正

* 🎨
2025-08-09 14:25:31 +09:00
かっこかり 0586dd98cb fix(deps): regenerate lockfile (#16384) 2025-08-09 14:20:18 +09:00
syuilo 504f886065 Update CHANGELOG.md 2025-08-09 14:14:16 +09:00
Sayamame-beans 2931eb0aad Fix: チャンネルのハイライトページにノートが表示されない問題を修正 (#16364)
* fix(frontend): unable to see channel's featured notes

* docs(changelog): update changelog

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-08-09 14:13:37 +09:00
anatawa12 103d5a4b44 fix frontend tests broken with aiscript 1.0.0 (#16377)
* test: update test for aiscript 1.0: line info in error

* test: update test for aiscript 1.0: keyword in object literal
2025-08-09 14:12:17 +09:00
かっこかり 785b85ee46 enhance(frontend): 画像エフェクトのUI改善 (#16191)
* enhance(frontend): 画像エフェクトの改善

* enhance: i18n colorClampAdvanced

* fix: missing translation

* enhance: i18n blockNoise

* fix lint

* fix: narrow down fx defs types

* fix

* fix: watermark用エフェクトは別で定義し直す

* fix lint

* ImageEffectorをwatermarkに隠蔽

* watermark関連の定義を完全に分離

* refactor

* fix

* ぼかし効果 -> スムージング

* refactor: remove unnecessary `as const`

* Update Changelog
2025-08-09 14:11:19 +09:00
anatawa12 8bd84a0ec4 fix: カラムの名前が正しくリスト/チャンネルの名前にならない問題 (#15987)
* fix: カラムの名前が正しくリスト/チャンネルの名前にならない問題

* changelog Fix: カラムの名前が正しくリスト/チャンネルの名前にならない問題を修正

* reduce requests to retrieve timeline name
2025-08-09 10:43:07 +09:00
renovate[bot] 9539995458 fix(deps): update [root] update dependencies (#16349)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-09 10:34:12 +09:00
syuilo e67ff36e57 enhance(frontend): AiScriptのcode-splittingが正しく行われるように 2025-08-08 21:50:05 +09:00
github-actions[bot] 96a165d729 Bump version to 2025.8.0-alpha.6 2025-08-08 12:36:36 +00:00
Sayamame-beans 215725a3ac Fix: SystemWebhook設定でsecretを空に出来ない問題を修正 (#16371)
* fix(backend): allow system-webhook secret to be empty

* docs(changelog): update changelog

* chore: run build-misskey-js-with-types
2025-08-08 21:35:02 +09:00
syuilo 3da04fcae4 New Crowdin updates (#16360)
* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Spanish)
2025-08-08 21:31:59 +09:00
tamaina 85e3e49688 fix(backend): Fix and create unit test of CleanRemoteNotesProcessorService (#16368)
* wip

* test(backend): CleanRemoteNotesProcessorService (basic)

* test(backend): CleanRemoteNotesProcessorService (advanced)

* ✌️

* a

* split initiator query

* no order by

* ???

* old → older
2025-08-08 21:31:31 +09:00
syuilo 076a83466e 🎨 2025-08-08 21:26:53 +09:00
syuilo aaf3f343ea Update about-misskey.vue 2025-08-08 21:20:23 +09:00
546 changed files with 12537 additions and 7410 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout head
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Setup Node.js
uses: actions/setup-node@v4.4.0
with:
@@ -18,7 +18,7 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
with:
submodules: true
persist-credentials: false
@@ -66,7 +66,7 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
with:
submodules: true
persist-credentials: false
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Check version
run: |
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Check
run: |
counter=0
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
check_copyright_year:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
- run: |
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
echo "Please change copyright year!"
@@ -28,7 +28,7 @@ jobs:
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Check allowed users
id: check-allowed-users
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
+2 -2
View File
@@ -15,7 +15,7 @@ jobs:
DOCKER_CONTENT_TRUST: 1
DOCKLE_VERSION: 0.4.14
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
- name: Download and install dockle v${{ env.DOCKLE_VERSION }}
run: |
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"
@@ -25,7 +25,7 @@ jobs:
cp ./compose_example.yml ./compose.yml
- run: |
docker compose up -d web
docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest
docker tag "$(docker compose images --format json web | jq -r '.[] | .ID')" misskey-web:latest
- run: |
cmd="dockle --exit-code 1 misskey-web:latest ${image_name}"
echo "> ${cmd}"
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
ref: refs/pull/${{ github.event.number }}/merge
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
ref: ${{ matrix.ref }}
submodules: true
+4 -4
View File
@@ -36,7 +36,7 @@ jobs:
pnpm_install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
fetch-depth: 0
submodules: true
@@ -69,7 +69,7 @@ jobs:
eslint-cache-version: v1
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
fetch-depth: 0
submodules: true
@@ -81,7 +81,7 @@ jobs:
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Restore eslint cache
uses: actions/cache@v4.2.3
uses: actions/cache@v4.2.4
with:
path: ${{ env.eslint-cache-path }}
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
@@ -99,7 +99,7 @@ jobs:
- sw
- misskey-js
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
fetch-depth: 0
submodules: true
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
fetch-depth: 0
submodules: true
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
+2 -2
View File
@@ -22,12 +22,12 @@ jobs:
NODE_OPTIONS: "--max_old_space_size=7168"
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
if: github.event_name != 'pull_request_target'
with:
fetch-depth: 0
submodules: true
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
if: github.event_name == 'pull_request_target'
with:
fetch-depth: 0
+3 -3
View File
@@ -50,7 +50,7 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
@@ -129,7 +129,7 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
@@ -173,7 +173,7 @@ jobs:
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
+2 -2
View File
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
@@ -76,7 +76,7 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
+77 -7
View File
@@ -1,3 +1,36 @@
## 2025.9.1
### General
- Enhance: 広告ごとにセンシティブフラグを設定できるようになりました
### Client
- Feat: アカウントのQRコードを表示・読み取りできるようになりました
- Enhance: チャットの日本語名称がダイレクトメッセージに戻るとともに、ベータ版機能ではなくなりました
- Enhance: 画像編集にマスクエフェクトを追加
- Enhance: ウォーターマークにアカウントのQRコードを追加できるように
- Enhance: 時刻計算のための基準値を一か所で管理するようにし、パフォーマンスを向上
- Fix: iOSで、デバイスがダークモードだと初回読み込み時にエラーになる問題を修正
### Server
-
## 2025.9.0
### Client
- Enhance: AiScriptAppウィジェットで構文エラーを検知してもダイアログではなくウィジェット内にエラーを表示するように
- Enhance: /flushページでサイトキャッシュをクリアできるようになりました
- Enhance: クリップ/リスト/アンテナ/ロール追加系メニュー項目において、表示件数を拡張
- Enhance: 「キャッシュを削除」ボタンでブラウザの内部キャッシュの削除も行えるように
- Enhance: Ctrlキー(Commandキー)を押下しながらリンクをクリックすると新しいタブで開くように
- Fix: プッシュ通知を有効にできない問題を修正
- Fix: RSSティッカーウィジェットが正しく動作しない問題を修正
- Fix: プロファイルを復元後アカウントの切り替えができない問題を修正
- Fix: エラー画像が横に引き伸ばされてしまう問題に対応
### Server
- Fix: webpなどの画像に対してセンシティブなメディアの検出が適用されていなかった問題を修正
## 2025.8.0
### Note
@@ -6,41 +39,78 @@
### General
- ノートを削除した際、関連するノートが同時に削除されないようになりました
- APIで、「replyIdが存在しているのにreplyがnull」や「renoteIdが存在しているのにrenoteがnull」であるという、今までにはなかったパターンが表れることになります
- 定期的に参照されていない古いリモートの投稿を削除する機能が実装されました(コントロールパネル→パフォーマンス→Remote Notes Cleaning)
- 既存のサーバーでは**デフォルトでオフ**、新規サーバーでは**デフォルトでオン**になります
- 定期的に古いリモートの投稿を削除する機能が実装されました
- コントロールパネル→パフォーマンス→Remote Notes Cleaning で有効化できます
- データベースの肥大化を防止することが可能です
- 既存のサーバーで当機能を有効化した場合は、処理量が多くなるため、一時的にストレージ使用量が増加する可能性があります。
- 増加量を抑えるには、最大処理継続時間をデフォルトより短くしてください。
- データベースサイズへの効果が見られない場合はautovacuumが有効になっているか確認してください
- サーバーの初期設定が完了するまでは連合がオンにならないようになりました
- 日本語における公開範囲名称の「ダイレクト」が「指名」に改称されました
- 実際の動作に即した名称になり、馴染みのない人でも理解しやすくなりました
- 他サービスにおける「ダイレクトメッセージ」に相当するMisskeyの機能は「チャット」ですが(過去のバージョンのMisskeyでも、当該機能は「チャット」ではなく「ダイレクトメッセージ」でした)、「ダイレクト投稿」という名称の機能が存在するとそちらがダイレクトメッセージ機能であるような誤解を生んでいました
- 今後、「チャット」の名称を「ダイレクトメッセージ」に戻す可能性があります
- mfm.jsをアップデートしました
- Enhance: Unicode 15.1 および 16.0 に収録されている絵文字に対応
- Enhance: acctに `.` が入っているユーザーのメンションに対応
- Fix: Unicode絵文字に隣接する異体字セレクタ(`U+FE0F`)が絵文字として認識される問題を修正
- Enhance: ユーザー検索をロールポリシーで制限できるように
### Client
- Feat: AiScriptが1.0に更新されました
- プラグインは1.0に対応したものが必要です
- Playはそのまま動作しますが、新規に作られるプリセットは1.0になります
- Feat: AiScriptが1.1.0に更新されました
- プラグインは1.xに対応したものが必要です
- Playはそのまま動作しますが、新規に作られるプリセットは1.xになります
- 以前のバージョンから無効化されていた note_view_interruptor が有効になりました
- ハンドラは同期的である必要があります
- Feat: セーフモード
- プラグイン・テーマ・カスタムCSSの使用でクライアントの起動に問題が発生した際に、これらを無効にして起動できます
- 以下の方法でセーフモードを起動できます
- `g` キーを連打する
- URLに`?safemode=true`を付ける
- PWAのショートカットで Safemode を選択して起動する
- Feat: 非ログイン時に表示されるトップページのスタイルを選択できるように
- コントロールパネル→ブランディング→エントランスページのスタイル
- Feat: ページのタブバーを下部に表示できるように
- Enhance: コントロールパネルを検索できるように
- Feat: (実験的)iOSでの触覚フィードバックを有効にできるように
- Feat: コントロールパネルを検索できるように
- Enhance: 「自動でもっと見る」オプションが有効になり、安定性が向上しました
- Enhance: トルコ語 (tr-TR) に対応
- Enhance: 言語別のスクリプトバンドルを生成するように
- Enhance: 不必要な翻訳データを読み込まなくなり、パフォーマンスが向上しました
- Enhance: 画像エフェクトのパラメータ名の多言語対応
- Enhance: ノートを非表示にする相対期間を1ヶ月単位で自由に指定できるように
- Enhance: メールアドレス確認画面のUIを改善
- Enhance: アイコンのスクロール追従を無効化する際の適用範囲を強化
- Enhance: レンダリングパフォーマンスの向上
- Enhance: 依存ソフトウェアの更新
- Fix: 投稿フォームでファイルのアップロードが中止または失敗した際のハンドリングを修正
- Fix: 一部の設定検索結果が存在しないパスになる問題を修正
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1171)
- Fix: テーマエディタが動作しない問題を修正
- Fix: チャンネルのハイライトページにノートが表示されない問題を修正
- Fix: カラムの名前が正しくリスト/チャンネルの名前にならない問題を修正
- Fix: 複数のメンションを1行に記述した場合に、サジェストが正しく表示されない問題を修正
- Fix: メンションとしての条件を満たしていても、特定の条件(`-`が含まれる場合など)で正しくサジェストされない問題を一部修正
- Fix: ユーザーの前後ノートを閲覧する機能が動作しない問題を修正
- Fix: 照会ダイアログでap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正
- Fix: アイコンのデコレーションを付ける際にデコレーションが表示されなくなる問題を修正
- Fix: タッチ操作時にマウスホバー時のユーザープレビューが開くことがある問題を修正
- Fix: 管理中アカウント一覧で正しい表示が行われない問題を修正
- Fix: lookupページでリモートURLを指定した際に正しく動作しない問題を修正
### Server
- Feat: サーバー管理コマンド
- `pnpm cli foo` の形式で実行可能です
- 現在以下のコマンドが利用可能です
- `reset-captcha` - CAPTCHA設定をリセットします
- Enhance: ノートの削除処理の効率化
- Enhance: 全体的なパフォーマンスの向上
- Enhance: 依存ソフトウェアの更新
- Enhance: `clips/list` APIがページネーションに対応しました
- Fix: `notes/mentions` で場合によっては並び順が正しく返されない問題を修正
- Fix: SystemWebhook設定でsecretを空に出来ない問題を修正
- Fix: 削除されたユーザーがチャットメッセージにリアクションしている場合`chat/history`などでエラーになる問題を修正
- Fix: Pageのアイキャッチ画像をドライブから消してもPageごと消えないように
- Fix: タイムラインAPIの withRenotes: false 時のレスポンスを修正
## 2025.7.0
+2 -2
View File
@@ -4,8 +4,8 @@
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { action } from '@storybook/addon-actions';
import { StoryObj } from '@storybook/vue3';
import { action } from 'storybook/actions';
import type { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw';
import { abuseUserReport } from '../packages/frontend/.storybook/fakes.js';
import { commonHandlers } from '../packages/frontend/.storybook/mocks.js';
+6
View File
@@ -1599,3 +1599,9 @@ _watermarkEditor:
type: "نوع"
image: "صور"
advanced: "متقدم"
_imageEffector:
_fxProps:
scale: "الحجم"
size: "الحجم"
color: "اللون"
opacity: "الشفافية"
+7
View File
@@ -1357,3 +1357,10 @@ _watermarkEditor:
text: "লেখা"
image: "ছবি"
advanced: "উন্নত"
_imageEffector:
_fxProps:
scale: "আকার"
size: "আকার"
color: "রং"
opacity: "অস্বচ্ছতা"
lightness: "উজ্জ্বল করুন"
+45 -3
View File
@@ -1054,6 +1054,7 @@ permissionDeniedError: "Operació no permesa "
permissionDeniedErrorDescription: "Aquest compte no té suficients permisos per dur a terme aquesta acció "
preset: "Predefinit"
selectFromPresets: "Escull des dels predefinits"
custom: "Personalitzat"
achievements: "Assoliments"
gotInvalidResponseError: "Resposta del servidor invàlida "
gotInvalidResponseErrorDescription: "No es pot contactar amb el servidor o potser es troba fora de línia per manteniment. Provar-ho de nou més tard."
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "Fent servir espais crearà expressions AND si l'ex
hiddenTags: "Etiquetes ocultes"
hiddenTagsDescription: "La visibilitat de totes les notes que continguin qualsevol de les paraules configurades seran, automàticament, afegides a \"Inici\". Pots llistar diferents paraules separant les per línies noves."
notesSearchNotAvailable: "La cerca de notes no es troba disponible."
usersSearchNotAvailable: "La cerca d'usuaris no està disponible."
license: "Llicència"
unfavoriteConfirm: "Esborrar dels favorits?"
myClips: "Els meus retalls"
@@ -1243,7 +1245,7 @@ releaseToRefresh: "Deixar anar per actualitzar"
refreshing: "Recarregant..."
pullDownToRefresh: "Llisca cap a baix per recarregar"
useGroupedNotifications: "Mostrar les notificacions agrupades "
signupPendingError: "Hi ha hagut un problema verificant l'adreça de correu electrònic. L'enllaç pot haver caducat."
emailVerificationFailedError: "Hem tingut un problema en verificar la teva adreça de correu electrònic. És probable que l'enllaç estigui caducat."
cwNotationRequired: "Si està activat \"Amagar contingut\" s'ha d'escriure una descripció "
doReaction: "Afegeix una reacció "
code: "Codi"
@@ -1374,6 +1376,7 @@ safeModeEnabled: "Mode segur activat"
pluginsAreDisabledBecauseSafeMode: "Els afegits no estan activats perquè el mode segur està activat."
customCssIsDisabledBecauseSafeMode: "El CSS personalitzat no s'aplica perquè el mode segur es troba activat."
themeIsDefaultBecauseSafeMode: "El tema predeterminat es farà servir mentre el mode segur estigui activat. Una vegada es desactivi el mode segur es restablirà el tema escollit."
thankYouForTestingBeta: "Gràcies per ajudar-nos a provar la versió beta!"
_order:
newest: "Més recent"
oldest: "Antigues primer"
@@ -1465,6 +1468,7 @@ _settings:
contentsUpdateFrequency_description2: "Quan s'activa el mode en temps real, el contingut s'actualitza en temps real, independentment d'aquesta configuració."
showUrlPreview: "Mostrar vista prèvia d'URL"
showAvailableReactionsFirstInNote: "Mostra les reacciones que pots fer servir al damunt"
showPageTabBarBottom: "Mostrar les pestanyes de les línies de temps a la part inferior"
_chat:
showSenderName: "Mostrar el nom del remitent"
sendOnEnter: "Introdueix per enviar"
@@ -1640,7 +1644,7 @@ _serverSettings:
reactionsBufferingDescription: "Quan s'activa aquesta opció millora bastant el rendiment en recuperar les línies de temps reduint la càrrega de la base. Com a contrapunt, augmentarà l'ús de memòria de Redís. Desactiva aquesta opció en cas de tenir un servidor amb poca memòria o si tens problemes d'inestabilitat."
remoteNotesCleaning: "Neteja automàtica de notes remotes"
remoteNotesCleaning_description: "Quan activis aquesta opció, periòdicament es netejaran les notes remotes que no es consultin, això evitarà que la base de dades se"
remoteNotesCleaningMaxProcessingDuration: "D'oració màxima del temps de funcionament del procés de neteja"
remoteNotesCleaningMaxProcessingDuration: "Duració màxima del temps de funcionament del procés de neteja"
remoteNotesCleaningExpiryDaysForEachNotes: "Duració mínima de conservació de les notes"
inquiryUrl: "URL de consulta "
inquiryUrlDescription: "Escriu adreça URL per al formulari de consulta per al mantenidor del servidor o una pàgina web amb el contacte d'informació."
@@ -1662,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "La publicació incondicional de tots els continguts del servidor a internet, incloent-hi els continguts remots rebuts pel servidor, comporta riscos. Això és extremadament important per els espectadors que desconeixen el caràcter descentralitzat dels continguts, ja que poden percebre erroneament els continguts remots com contingut generat per el propi servidor."
restartServerSetupWizardConfirm_title: "Vols tornar a executar l'assistent de configuració inicial del servidor?"
restartServerSetupWizardConfirm_text: "Algunes configuracions actuals seran restablertes."
entrancePageStyle: "Estil de la pàgina d'inici"
showTimelineForVisitor: "Mostrar la línia de temps"
showActivitiesForVisitor: "Mostrar activitat"
_userGeneratedContentsVisibilityForVisitor:
all: "Tot obert al públic "
localOnly: "Només es publiquen els continguts locals, el contingut remot es manté privat"
@@ -1998,6 +2005,7 @@ _role:
descriptionOfRateLimitFactor: "Límits baixos són menys restrictius, límits alts són més restrictius."
canHideAds: "Pot amagar la publicitat"
canSearchNotes: "Pot cercar notes"
canSearchUsers: "Pot cercar usuaris"
canUseTranslator: "Pot fer servir el traductor"
avatarDecorationLimit: "Nombre màxim de decoracions que es poden aplicar els avatars"
canImportAntennas: "Autoritza la importació d'antenes "
@@ -2270,6 +2278,7 @@ _time:
minute: "Minut(s)"
hour: "Hor(a)(es)"
day: "Di(a)(es)"
month: "Mes(os)"
_2fa:
alreadyRegistered: "J has registrat un dispositiu d'autenticació de doble factor."
registerTOTP: "Registrar una aplicació autenticadora"
@@ -3163,10 +3172,10 @@ _watermarkEditor:
type: "Tipus"
image: "Imatges"
advanced: "Avançat"
angle: "Angle"
stripe: "Bandes"
stripeWidth: "Amplada de la banda"
stripeFrequency: "Freqüència de la banda"
angle: "Angle"
polkadot: "Lunars"
checker: "Escacs"
polkadotMainDotOpacity: "Opacitat del lunar principal"
@@ -3178,6 +3187,7 @@ _imageEffector:
title: "Efecte"
addEffect: "Afegeix un efecte"
discardChangesConfirm: "Vols descartar els canvis i sortir?"
nothingToConfigure: "No hi ha opcions de configuració disponibles"
_fxs:
chromaticAberration: "Aberració cromàtica"
glitch: "Glitch"
@@ -3195,6 +3205,38 @@ _imageEffector:
checker: "Escacs"
blockNoise: "Bloqueig de soroll"
tearing: "Trencament d'imatge "
_fxProps:
angle: "Angle"
scale: "Mida"
size: "Mida"
color: "Color"
opacity: "Opacitat"
normalize: "Normalitzar"
amount: "Quantitat"
lightness: "Brillantor"
contrast: "Contrast"
hue: "Tonalitat"
brightness: "Brillantor"
saturation: "Saturació"
max: "Màxim"
min: "Mínim"
direction: "Direcció "
phase: "Fase"
frequency: "Freqüència "
strength: "Intensitat"
glitchChannelShift: "Canvi de canal "
seed: "Llindar"
redComponent: "Component vermell"
greenComponent: "Component verd"
blueComponent: "Component blau"
threshold: "Llindar"
centerX: "Centre de X"
centerY: "Centre de Y"
zoomLinesSmoothing: "Suavitzat"
zoomLinesSmoothingDescription: "Els paràmetres de suavitzat i amplada de línia en augmentar no es poden fer servir junts."
zoomLinesThreshold: "Amplada de línia a l'augmentar "
zoomLinesMaskSize: "Diàmetre del centre"
zoomLinesBlack: "Obscurir"
drafts: "Esborrany "
_drafts:
select: "Seleccionar esborrany"
+7
View File
@@ -2053,3 +2053,10 @@ _watermarkEditor:
type: "Typ"
image: "Obrázky"
advanced: "Pokročilé"
_imageEffector:
_fxProps:
scale: "Velikost"
size: "Velikost"
color: "Barva"
opacity: "Průhlednost"
lightness: "Zesvětlit"
+8 -2
View File
@@ -1243,7 +1243,6 @@ releaseToRefresh: "Zum Aktualisieren loslassen"
refreshing: "Wird aktualisiert..."
pullDownToRefresh: "Zum Aktualisieren ziehen"
useGroupedNotifications: "Benachrichtigungen gruppieren"
signupPendingError: "Beim Überprüfen der Mailadresse ist etwas schiefgelaufen. Der Link könnte abgelaufen sein."
cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden."
doReaction: "Reagieren"
code: "Code"
@@ -3147,10 +3146,10 @@ _watermarkEditor:
type: "Art"
image: "Bilder"
advanced: "Fortgeschritten"
angle: "Winkel"
stripe: "Streifen"
stripeWidth: "Linienbreite"
stripeFrequency: "Linienanzahl"
angle: "Winkel"
polkadot: "Punktmuster"
polkadotMainDotOpacity: "Deckkraft des Hauptpunktes"
polkadotMainDotRadius: "Größe des Hauptpunktes"
@@ -3173,6 +3172,13 @@ _imageEffector:
distort: "Verzerrung"
stripe: "Streifen"
polkadot: "Punktmuster"
_fxProps:
angle: "Winkel"
scale: "Größe"
size: "Größe"
color: "Farbe"
opacity: "Transparenz"
lightness: "Erhellen"
drafts: "Entwurf"
_drafts:
select: "Entwurf auswählen"
+54 -12
View File
@@ -1054,6 +1054,7 @@ permissionDeniedError: "Operation denied"
permissionDeniedErrorDescription: "This account does not have the permission to perform this action."
preset: "Preset"
selectFromPresets: "Choose from presets"
custom: "Custom"
achievements: "Achievements"
gotInvalidResponseError: "Invalid server response"
gotInvalidResponseErrorDescription: "The server may be unreachable or undergoing maintenance. Please try again later."
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "Using spaces will create AND expressions and surro
hiddenTags: "Hidden hashtags"
hiddenTagsDescription: "Select tags which will not shown on trend list.\nMultiple tags could be registered by lines."
notesSearchNotAvailable: "Note search is unavailable."
usersSearchNotAvailable: "User search is not available."
license: "License"
unfavoriteConfirm: "Really remove from favorites?"
myClips: "My clips"
@@ -1216,8 +1218,8 @@ showRepliesToOthersInTimeline: "Show replies to others in timeline"
hideRepliesToOthersInTimeline: "Hide replies to others from timeline"
showRepliesToOthersInTimelineAll: "Show replies to others from everyone you follow in timeline"
hideRepliesToOthersInTimelineAll: "Hide replies to others from everyone you follow in timeline"
confirmShowRepliesAll: "This operation is irreversible. Would you really like to show replies to others from everyone you follow in your timeline?"
confirmHideRepliesAll: "This operation is irreversible. Would you really like to hide replies to others from everyone you follow in your timeline?"
confirmShowRepliesAll: "Are you sure you want to show replies from everyone you follow in your timeline? This action is irreversible."
confirmHideRepliesAll: "Are you sure you want to hide replies from everyone you follow in your timeline? This action is irreversible."
externalServices: "External Services"
sourceCode: "Source code"
sourceCodeIsNotYetProvided: "Source code is not yet available. Contact the administrator to fix this problem."
@@ -1243,7 +1245,7 @@ releaseToRefresh: "Release to refresh"
refreshing: "Refreshing..."
pullDownToRefresh: "Pull down to refresh"
useGroupedNotifications: "Display grouped notifications"
signupPendingError: "There was a problem verifying the email address. The link may have expired."
emailVerificationFailedError: "A problem occurred while verifying your email address. The link may have expired."
cwNotationRequired: "If \"Hide content\" is enabled, a description must be provided."
doReaction: "Add reaction"
code: "Code"
@@ -1374,6 +1376,7 @@ safeModeEnabled: "Safe mode is enabled"
pluginsAreDisabledBecauseSafeMode: "All plugins are disabled because safe mode is enabled."
customCssIsDisabledBecauseSafeMode: "Custom CSS is not applied because safe mode is enabled."
themeIsDefaultBecauseSafeMode: "While safe mode is active, the default theme is used. Disabling safe mode will revert these changes."
thankYouForTestingBeta: "Thank you for helping us test the beta version!"
_order:
newest: "Newest First"
oldest: "Oldest First"
@@ -1465,6 +1468,7 @@ _settings:
contentsUpdateFrequency_description2: "When real-time mode is on, content is updated in real time regardless of this setting."
showUrlPreview: "Show URL preview"
showAvailableReactionsFirstInNote: "Show available reactions at the top."
showPageTabBarBottom: "Show page tab bar at the bottom"
_chat:
showSenderName: "Show sender's name"
sendOnEnter: "Press Enter to send"
@@ -1662,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Unconditionally publishing all content on the server to the Internet, including remote content received by the server is risky. This is especially important for guests who are unaware of the distributed nature of the content, as they may mistakenly believe that even remote content is content created by users on the server."
restartServerSetupWizardConfirm_title: "Restart server setup wizard?"
restartServerSetupWizardConfirm_text: "Some current settings will be reset."
entrancePageStyle: "Entrance page style"
showTimelineForVisitor: "Show timeline"
showActivitiesForVisitor: "Show activities"
_userGeneratedContentsVisibilityForVisitor:
all: "Everything is public"
localOnly: "Only local content is published, remote content is kept private"
@@ -1998,19 +2005,20 @@ _role:
descriptionOfRateLimitFactor: "Lower rate limits are less restrictive, higher ones more restrictive. "
canHideAds: "Can hide ads"
canSearchNotes: "Usage of note search"
canSearchUsers: "User search"
canUseTranslator: "Translator usage"
avatarDecorationLimit: "Maximum number of avatar decorations that can be applied"
canImportAntennas: "Allow importing antennas"
canImportBlocking: "Allow importing blocking"
canImportFollowing: "Allow importing following"
canImportMuting: "Allow importing muting"
canImportUserLists: "Allow importing lists"
chatAvailability: "Allow Chat"
avatarDecorationLimit: "Maximum number of avatar decorations"
canImportAntennas: "Can import antennas"
canImportBlocking: "Can import blocking"
canImportFollowing: "Can import following"
canImportMuting: "Can import muting"
canImportUserLists: "Can import lists"
chatAvailability: "Chat"
uploadableFileTypes: "Uploadable file types"
uploadableFileTypes_caption: "Specifies the allowed MIME/file types. Multiple MIME types can be specified by separating them with a new line, and wildcards can be specified with an asterisk (*). (e.g., image/*)"
uploadableFileTypes_caption2: "Some files types might fail to be detected. To allow such files, add {x} to the specification."
noteDraftLimit: "Number of possible drafts of server notes"
watermarkAvailable: "Availability of watermark function"
watermarkAvailable: "Watermark function"
_condition:
roleAssignedTo: "Assigned to manual roles"
isLocal: "Local user"
@@ -2270,6 +2278,7 @@ _time:
minute: "Minute(s)"
hour: "Hour(s)"
day: "Day(s)"
month: "Month(s)"
_2fa:
alreadyRegistered: "You have already registered a 2-factor authentication device."
registerTOTP: "Register authenticator app"
@@ -3163,10 +3172,10 @@ _watermarkEditor:
type: "Type"
image: "Images"
advanced: "Advanced"
angle: "Angle"
stripe: "Stripes"
stripeWidth: "Line width"
stripeFrequency: "Lines count"
angle: "Angle"
polkadot: "Polkadot"
checker: "Checker"
polkadotMainDotOpacity: "Opacity of the main dot"
@@ -3178,6 +3187,7 @@ _imageEffector:
title: "Effects"
addEffect: "Add Effects"
discardChangesConfirm: "Are you sure you want to leave? You have unsaved changes."
nothingToConfigure: "No configurable options available"
_fxs:
chromaticAberration: "Chromatic Aberration"
glitch: "Glitch"
@@ -3195,6 +3205,38 @@ _imageEffector:
checker: "Checker"
blockNoise: "Block Noise"
tearing: "Tearing"
_fxProps:
angle: "Angle"
scale: "Size"
size: "Size"
color: "Color"
opacity: "Opacity"
normalize: "Normalize"
amount: "Amount"
lightness: "Lighten"
contrast: "Contrast"
hue: "Hue"
brightness: "Brightness"
saturation: "Saturation"
max: "Maximum"
min: "Minimum"
direction: "Direction"
phase: "Phase"
frequency: "Frequency"
strength: "Strength"
glitchChannelShift: "Channel shift"
seed: "Seed value"
redComponent: "Red component"
greenComponent: "Green component"
blueComponent: "Blue component"
threshold: "Threshold"
centerX: "Center X"
centerY: "Center Y"
zoomLinesSmoothing: "Smoothing"
zoomLinesSmoothingDescription: "Smoothing and zoom line width cannot be used together."
zoomLinesThreshold: "Zoom line width"
zoomLinesMaskSize: "Center diameter"
zoomLinesBlack: "Make black"
drafts: "Drafts"
_drafts:
select: "Select Draft"
+45 -3
View File
@@ -1054,6 +1054,7 @@ permissionDeniedError: "Operación denegada"
permissionDeniedErrorDescription: "Esta cuenta no tiene permisos para hacer esa acción."
preset: "Predefinido"
selectFromPresets: "Escoger desde predefinidos"
custom: "Personalizado"
achievements: "Logros"
gotInvalidResponseError: "Respuesta del servidor inválida"
gotInvalidResponseErrorDescription: "Puede que el servidor esté caído o en mantenimiento. Favor de intentar más tarde"
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "Si se usan espacios se crearán expresiones AND y
hiddenTags: "Hashtags ocultos"
hiddenTagsDescription: "Selecciona las etiquetas que no se mostrarán en tendencias. Una etiqueta por línea."
notesSearchNotAvailable: "No se puede buscar una nota"
usersSearchNotAvailable: "La búsqueda de usuarios no está disponible."
license: "Licencia"
unfavoriteConfirm: "¿Desea quitar de favoritos?"
myClips: "Mis clips"
@@ -1243,7 +1245,7 @@ releaseToRefresh: "Soltar para recargar"
refreshing: "Recargando..."
pullDownToRefresh: "Tira hacia abajo para recargar"
useGroupedNotifications: "Mostrar notificaciones agrupadas"
signupPendingError: "Ha habido un problema al verificar tu dirección de correo electrónico. Es posible que el enlace haya caducado."
emailVerificationFailedError: "Se ha producido un error al confirmar tu dirección de correo electrónico. Es posible que el enlace haya caducado."
cwNotationRequired: "Si se ha activado \"ocultar contenido\", es necesario proporcionar una descripción."
doReaction: "Añadir reacción"
code: "Código"
@@ -1374,6 +1376,7 @@ safeModeEnabled: "El modo seguro está activado"
pluginsAreDisabledBecauseSafeMode: "El modo seguro está activado, por lo que todos los plugins están desactivados."
customCssIsDisabledBecauseSafeMode: "El modo seguro está activado, por lo que no se aplica el CSS personalizado."
themeIsDefaultBecauseSafeMode: "Mientras el modo seguro esté activado, se utilizará el tema predeterminado. Cuando se desactive el modo seguro, se volverá al tema original."
thankYouForTestingBeta: "¡Gracias por tu colaboración en la prueba de la versión beta!"
_order:
newest: "Los más recientes primero"
oldest: "Los más antiguos primero"
@@ -1465,6 +1468,7 @@ _settings:
contentsUpdateFrequency_description2: "Cuando el modo en tiempo real está activado, el contenido se actualiza en tiempo real independientemente de esta configuración."
showUrlPreview: "Mostrar la vista previa de la URL"
showAvailableReactionsFirstInNote: "Mostrar las reacciones disponibles en la parte superior."
showPageTabBarBottom: "Mostrar la barra de pestañas de la página en la parte inferior."
_chat:
showSenderName: "Mostrar el nombre del remitente"
sendOnEnter: "Intro para enviar"
@@ -1662,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Publicar incondicionalmente todo el contenido del servidor en Internet, incluido el contenido remoto recibido por el servidor, es arriesgado. Esto es especialmente importante para los invitados que desconocen la naturaleza distribuida del contenido, ya que pueden creer erróneamente que incluso el contenido remoto es contenido creado por usuarios en el servidor."
restartServerSetupWizardConfirm_title: "¿Reiniciar el asistente de configuración del servidor?"
restartServerSetupWizardConfirm_text: "Algunas configuraciones actuales se restablecerán"
entrancePageStyle: "Estilo de la página de inicio"
showTimelineForVisitor: "Mostrar la línea de tiempo"
showActivitiesForVisitor: "Mostrar actividades"
_userGeneratedContentsVisibilityForVisitor:
all: "Todo es público."
localOnly: "Sólo se publica el contenido local, el remoto se mantiene privado"
@@ -1998,6 +2005,7 @@ _role:
descriptionOfRateLimitFactor: "Límites más bajos son menos restrictivos, más altos menos restrictivos"
canHideAds: "Puede ocultar anuncios"
canSearchNotes: "Uso de la búsqueda de notas"
canSearchUsers: "Uso de la búsqueda de usuarios"
canUseTranslator: "Uso de traductor"
avatarDecorationLimit: "Número máximo de decoraciones de avatar"
canImportAntennas: "Permitir la importación de antenas"
@@ -2129,7 +2137,7 @@ _aboutMisskey:
_displayOfSensitiveMedia:
respect: "Esconder medios marcados como sensibles"
ignore: "Mostrar medios marcados como sensibles"
force: "Esconder todala multimedia"
force: "Esconder toda la multimedia"
_instanceTicker:
none: "No mostrar"
remote: "Mostrar a usuarios remotos"
@@ -2270,6 +2278,7 @@ _time:
minute: "Minutos"
hour: "Horas"
day: "Días"
month: "Mes(es)"
_2fa:
alreadyRegistered: "Ya has completado la configuración."
registerTOTP: "Registrar aplicación autenticadora"
@@ -3163,10 +3172,10 @@ _watermarkEditor:
type: "Tipo"
image: "Imágenes"
advanced: "Avanzado"
angle: "Ángulo"
stripe: "Rayas"
stripeWidth: "Anchura de línea"
stripeFrequency: "Número de líneas."
angle: "Ángulo"
polkadot: "Lunares"
checker: "verificador"
polkadotMainDotOpacity: "Opacidad del círculo principal"
@@ -3178,6 +3187,7 @@ _imageEffector:
title: "Efecto"
addEffect: "Añadir Efecto"
discardChangesConfirm: "¿Ignorar cambios y salir?"
nothingToConfigure: "No hay opciones configurables disponibles."
_fxs:
chromaticAberration: "Aberración Cromática"
glitch: "Glitch"
@@ -3195,6 +3205,38 @@ _imageEffector:
checker: "Corrector"
blockNoise: "Bloquear Ruido"
tearing: "Rasgado de Imagen (Tearing)"
_fxProps:
angle: "Ángulo"
scale: "Tamaño"
size: "Tamaño"
color: "Color"
opacity: "Opacidad"
normalize: "Normalización"
amount: "Cantidad"
lightness: "Brillo"
contrast: "Contraste"
hue: "Tonalidad"
brightness: "Brillo"
saturation: "Saturación"
max: "Valor máximo"
min: "Valor mínimo"
direction: "Dirección"
phase: "Fase"
frequency: "Frecuencia"
strength: "Intensidad"
glitchChannelShift: "cambio de canal de imagen"
seed: "Valor de la semilla"
redComponent: "Componente rojo"
greenComponent: "Componente Verde"
blueComponent: "Componente Azul"
threshold: "Umbral"
centerX: "Centrar X"
centerY: "Centrar Y"
zoomLinesSmoothing: "Suavizado"
zoomLinesSmoothingDescription: "El suavizado y el ancho de línea de zoom no se pueden utilizar juntos."
zoomLinesThreshold: "Ancho de línea del zoom"
zoomLinesMaskSize: "Diámetro del centro"
zoomLinesBlack: "Hacer oscuro"
drafts: "Borrador"
_drafts:
select: "Seleccionar borradores"
+8 -1
View File
@@ -1208,7 +1208,6 @@ releaseToRefresh: "Relâcher pour rafraîchir"
refreshing: "Rafraîchissement..."
pullDownToRefresh: "Tirer vers le bas pour rafraîchir"
useGroupedNotifications: "Grouper les notifications"
signupPendingError: "Un problème est survenu lors de la vérification de votre adresse e-mail. Le lien a peut-être expiré."
cwNotationRequired: "Si « Masquer le contenu » est activé, une description doit être fournie."
doReaction: "Réagir"
code: "Code"
@@ -2372,3 +2371,11 @@ _watermarkEditor:
image: "Images"
advanced: "Avancé"
angle: "Angle"
_imageEffector:
_fxProps:
angle: "Angle"
scale: "Taille"
size: "Taille"
color: "Couleur"
opacity: "Transparence"
lightness: "Clair"
+8 -1
View File
@@ -1212,7 +1212,6 @@ releaseToRefresh: "Lepaskan untuk memuat ulang"
refreshing: "Sedang memuat ulang..."
pullDownToRefresh: "Tarik ke bawah untuk memuat ulang"
useGroupedNotifications: "Tampilkan notifikasi secara dikelompokkan"
signupPendingError: "Terdapat masalah ketika memverifikasi alamat surel. Tautan kemungkinan telah kedaluwarsa."
cwNotationRequired: "Jika \"Sembunyikan konten\" diaktifkan, deskripsi harus disediakan."
doReaction: "Tambahkan reaksi"
code: "Kode"
@@ -2627,3 +2626,11 @@ _watermarkEditor:
image: "Gambar"
advanced: "Tingkat lanjut"
angle: "Sudut"
_imageEffector:
_fxProps:
angle: "Sudut"
scale: "Ukuran"
size: "Ukuran"
color: "Warna"
opacity: "Opasitas"
lightness: "Menerangkan"
+308 -48
View File
@@ -1227,7 +1227,7 @@ export interface Locale extends ILocale {
*/
"noMoreHistory": string;
/**
*
*
*/
"startChat": string;
/**
@@ -1927,7 +1927,7 @@ export interface Locale extends ILocale {
*/
"markAsReadAllUnreadNotes": string;
/**
*
*
*/
"markAsReadAllTalkMessages": string;
/**
@@ -4234,6 +4234,10 @@ export interface Locale extends ILocale {
*
*/
"selectFromPresets": string;
/**
*
*/
"custom": string;
/**
*
*/
@@ -4386,6 +4390,10 @@ export interface Locale extends ILocale {
*
*/
"notesSearchNotAvailable": string;
/**
*
*/
"usersSearchNotAvailable": string;
/**
*
*/
@@ -4993,7 +5001,7 @@ export interface Locale extends ILocale {
/**
*
*/
"signupPendingError": string;
"emailVerificationFailedError": string;
/**
*
*/
@@ -5382,6 +5390,14 @@ export interface Locale extends ILocale {
*
*/
"chat": string;
/**
*
*/
"directMessage": string;
/**
*
*/
"directMessage_short": string;
/**
*
*/
@@ -5517,6 +5533,14 @@ export interface Locale extends ILocale {
* 使
*/
"themeIsDefaultBecauseSafeMode": string;
/**
*
*/
"thankYouForTestingBeta": string;
/**
*
*/
"createUserSpecifiedNote": string;
"_order": {
/**
*
@@ -5528,6 +5552,10 @@ export interface Locale extends ILocale {
"oldest": string;
};
"_chat": {
/**
*
*/
"messages": string;
/**
*
*/
@@ -5537,36 +5565,36 @@ export interface Locale extends ILocale {
*/
"newMessage": string;
/**
*
*
*/
"individualChat": string;
/**
*
*
*/
"individualChat_description": string;
/**
*
*
*/
"roomChat": string;
/**
*
*
*
*
*/
"roomChat_description": string;
/**
*
*
*/
"createRoom": string;
/**
*
*
*/
"inviteUserToChat": string;
/**
*
*
*/
"yourRooms": string;
/**
*
*
*/
"joiningRooms": string;
/**
@@ -5586,7 +5614,7 @@ export interface Locale extends ILocale {
*/
"noHistory": string;
/**
*
*
*/
"noRooms": string;
/**
@@ -5606,7 +5634,7 @@ export interface Locale extends ILocale {
*/
"ignore": string;
/**
* 退
* 退
*/
"leave": string;
/**
@@ -5630,35 +5658,35 @@ export interface Locale extends ILocale {
*/
"newline": string;
/**
*
*
*/
"muteThisRoom": string;
/**
*
*
*/
"deleteRoom": string;
/**
*
*
*/
"chatNotAvailableForThisAccountOrServer": string;
/**
*
*
*/
"chatIsReadOnlyForThisAccountOrServer": string;
/**
* 使
* 使
*/
"chatNotAvailableInOtherAccount": string;
/**
*
*
*/
"cannotChatWithTheUser": string;
/**
* 使
* 使
*/
"cannotChatWithTheUser_description": string;
/**
*
*
*/
"youAreNotAMemberOfThisRoomButInvited": string;
/**
@@ -5666,31 +5694,31 @@ export interface Locale extends ILocale {
*/
"doYouAcceptInvitation": string;
/**
*
*
*/
"chatWithThisUser": string;
/**
*
*
*/
"thisUserAllowsChatOnlyFromFollowers": string;
/**
*
*
*/
"thisUserAllowsChatOnlyFromFollowing": string;
/**
*
*
*/
"thisUserAllowsChatOnlyFromMutualFollowing": string;
/**
*
*
*/
"thisUserNotAllowedChatAnyone": string;
/**
*
*
*/
"chatAllowedUsers": string;
/**
*
*
*/
"chatAllowedUsers_note": string;
"_chatAllowedUsers": {
@@ -6519,7 +6547,7 @@ export interface Locale extends ILocale {
*/
"remoteNotesCleaning": string;
/**
* 稿
* 稿
*/
"remoteNotesCleaning_description": string;
/**
@@ -6610,6 +6638,18 @@ export interface Locale extends ILocale {
*
*/
"restartServerSetupWizardConfirm_text": string;
/**
*
*/
"entrancePageStyle": string;
/**
*
*/
"showTimelineForVisitor": string;
/**
*
*/
"showActivitiesForVisitor": string;
"_userGeneratedContentsVisibilityForVisitor": {
/**
*
@@ -7799,6 +7839,10 @@ export interface Locale extends ILocale {
*
*/
"canSearchNotes": string;
/**
*
*/
"canSearchUsers": string;
/**
*
*/
@@ -7828,7 +7872,7 @@ export interface Locale extends ILocale {
*/
"canImportUserLists": string;
/**
*
*
*/
"chatAvailability": string;
/**
@@ -8678,7 +8722,7 @@ export interface Locale extends ILocale {
*/
"badge": string;
/**
*
*
*/
"messageBg": string;
/**
@@ -8705,7 +8749,7 @@ export interface Locale extends ILocale {
*/
"reaction": string;
/**
*
*
*/
"chatMessage": string;
};
@@ -8828,6 +8872,10 @@ export interface Locale extends ILocale {
*
*/
"day": string;
/**
*
*/
"month": string;
};
"_2fa": {
/**
@@ -8985,11 +9033,11 @@ export interface Locale extends ILocale {
*/
"write:following": string;
/**
*
*
*/
"read:messaging": string;
/**
*
*
*/
"write:messaging": string;
/**
@@ -9281,11 +9329,11 @@ export interface Locale extends ILocale {
*/
"write:report-abuse": string;
/**
*
*
*/
"write:chat": string;
/**
*
*
*/
"read:chat": string;
};
@@ -9511,7 +9559,7 @@ export interface Locale extends ILocale {
*/
"birthdayFollowings": string;
/**
*
*
*/
"chat": string;
};
@@ -10251,7 +10299,7 @@ export interface Locale extends ILocale {
*/
"roleAssigned": string;
/**
*
*
*/
"chatRoomInvitationReceived": string;
/**
@@ -10364,7 +10412,7 @@ export interface Locale extends ILocale {
*/
"roleAssigned": string;
/**
*
*
*/
"chatRoomInvitationReceived": string;
/**
@@ -10546,7 +10594,7 @@ export interface Locale extends ILocale {
*/
"roleTimeline": string;
/**
*
*
*/
"chat": string;
};
@@ -10913,7 +10961,7 @@ export interface Locale extends ILocale {
*/
"deleteGalleryPost": string;
/**
*
*
*/
"deleteChatRoom": string;
/**
@@ -12000,11 +12048,11 @@ export interface Locale extends ILocale {
*/
"youCanConfigureMoreFederationSettingsLater": string;
/**
*
*
*/
"remoteContentsCleaning": string;
/**
*
*
*/
"remoteContentsCleaning_description": string;
/**
@@ -12187,10 +12235,18 @@ export interface Locale extends ILocale {
*
*/
"text": string;
/**
*
*/
"qr": string;
/**
*
*/
"position": string;
/**
*
*/
"margin": string;
/**
*
*/
@@ -12203,6 +12259,10 @@ export interface Locale extends ILocale {
*
*/
"advanced": string;
/**
*
*/
"angle": string;
/**
*
*/
@@ -12215,10 +12275,6 @@ export interface Locale extends ILocale {
*
*/
"stripeFrequency": string;
/**
*
*/
"angle": string;
/**
*
*/
@@ -12247,6 +12303,10 @@ export interface Locale extends ILocale {
*
*/
"polkadotSubDotDivisions": string;
/**
* URLになります
*/
"leaveBlankToAccountUrl": string;
};
"_imageEffector": {
/**
@@ -12261,6 +12321,10 @@ export interface Locale extends ILocale {
*
*/
"discardChangesConfirm": string;
/**
*
*/
"nothingToConfigure": string;
"_fxs": {
/**
*
@@ -12326,6 +12390,140 @@ export interface Locale extends ILocale {
*
*/
"tearing": string;
/**
* ()
*/
"fillSquare": string;
};
"_fxProps": {
/**
*
*/
"angle": string;
/**
*
*/
"scale": string;
/**
*
*/
"size": string;
/**
*
*/
"offset": string;
/**
*
*/
"color": string;
/**
*
*/
"opacity": string;
/**
*
*/
"normalize": string;
/**
*
*/
"amount": string;
/**
*
*/
"lightness": string;
/**
*
*/
"contrast": string;
/**
*
*/
"hue": string;
/**
*
*/
"brightness": string;
/**
*
*/
"saturation": string;
/**
*
*/
"max": string;
/**
*
*/
"min": string;
/**
*
*/
"direction": string;
/**
*
*/
"phase": string;
/**
*
*/
"frequency": string;
/**
*
*/
"strength": string;
/**
*
*/
"glitchChannelShift": string;
/**
*
*/
"seed": string;
/**
*
*/
"redComponent": string;
/**
*
*/
"greenComponent": string;
/**
*
*/
"blueComponent": string;
/**
*
*/
"threshold": string;
/**
* X
*/
"centerX": string;
/**
* Y
*/
"centerY": string;
/**
*
*/
"zoomLinesSmoothing": string;
/**
*
*/
"zoomLinesSmoothingDescription": string;
/**
*
*/
"zoomLinesThreshold": string;
/**
*
*/
"zoomLinesMaskSize": string;
/**
*
*/
"zoomLinesBlack": string;
};
};
/**
@@ -12386,6 +12584,68 @@ export interface Locale extends ILocale {
*/
"listDrafts": string;
};
/**
*
*/
"qr": string;
"_qr": {
/**
*
*/
"showTabTitle": string;
/**
*
*/
"readTabTitle": string;
/**
* {name} {acct}
*/
"shareTitle": ParameterizedString<"name" | "acct">;
/**
* Fediverseで私をフォローしてください
*/
"shareText": string;
/**
*
*/
"chooseCamera": string;
/**
*
*/
"cannotToggleFlash": string;
/**
*
*/
"turnOnFlash": string;
/**
*
*/
"turnOffFlash": string;
/**
*
*/
"startQr": string;
/**
*
*/
"stopQr": string;
/**
* QRコードが見つかりません
*/
"noQrCodeFound": string;
/**
*
*/
"scanFile": string;
/**
*
*/
"raw": string;
/**
* MFM
*/
"mfm": string;
};
}
declare const locales: {
[lang: string]: Locale;
+113 -58
View File
@@ -139,7 +139,7 @@ overwriteFromPinnedEmojis: "Sovrascrivi con le impostazioni globali"
reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere."
rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note"
attachCancel: "Rimuovi allegato"
deleteFile: "File da Drive eliminato"
deleteFile: "Elimina un file dal Drive"
markAsSensitive: "Segna come esplicito"
unmarkAsSensitive: "Non segnare come esplicito "
enterFileName: "Nome del file"
@@ -1054,6 +1054,7 @@ permissionDeniedError: "Errore, attività non autorizzata"
permissionDeniedErrorDescription: "Non si dispone dell'autorizzazione per eseguire questa operazione."
preset: "Preimpostato"
selectFromPresets: "Seleziona preimpostato"
custom: "Personalizzato"
achievements: "Conquiste"
gotInvalidResponseError: "Risposta del server non valida"
gotInvalidResponseErrorDescription: "Il server potrebbe essere irraggiungibile o in manutenzione. Riprova più tardi."
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "Gli spazi creano la relazione \"E\" tra parole (qu
hiddenTags: "Hashtag nascosti"
hiddenTagsDescription: "Impedire la visualizzazione del tag impostato nei trend. Puoi impostare più valori, uno per riga."
notesSearchNotAvailable: "Non è possibile cercare tra le Note."
usersSearchNotAvailable: "La ricerca profili non è disponibile."
license: "Licenza"
unfavoriteConfirm: "Vuoi davvero rimuovere la preferenza?"
myClips: "Le mie Clip"
@@ -1198,7 +1200,7 @@ replies: "Risposte"
renotes: "Rinota"
loadReplies: "Leggi le risposte"
loadConversation: "Leggi la conversazione"
pinnedList: "Elenco in primo piano"
pinnedList: "Lista in primo piano"
keepScreenOn: "Mantenere lo schermo acceso"
verifiedLink: "Abbiamo confermato la validità di questo collegamento"
notifyNotes: "Notifica nuove Note"
@@ -1243,7 +1245,7 @@ releaseToRefresh: "Rilascia per aggiornare"
refreshing: "Aggiornamento..."
pullDownToRefresh: "Trascinare per aggiornare"
useGroupedNotifications: "Mostra le notifiche raggruppate"
signupPendingError: "Si è verificato un problema durante la verifica del tuo indirizzo email. Potrebbe essere scaduto il collegamento temporaneo."
emailVerificationFailedError: "La verifica dell'indirizzo e-mail non è andata a buon fine. Il link potrebbe essere scaduto."
cwNotationRequired: "Devi indicare perché il contenuto è indicato come esplicito."
doReaction: "Reagisci"
code: "Codice"
@@ -1370,6 +1372,11 @@ defaultImageCompressionLevel: "Livello predefinito di compressione immagini"
defaultImageCompressionLevel_description: "La compressione diminuisce la qualità dell'immagine, poca compressione mantiene alta qualità delle immagini. Aumentandola, si riducono le dimensioni del file, a discapito della qualità dell'immagine."
inMinutes: "min"
inDays: "giorni"
safeModeEnabled: "La modalità sicura è attiva"
pluginsAreDisabledBecauseSafeMode: "Tutti i plugin sono disattivati, poiché la modalità sicura è attiva."
customCssIsDisabledBecauseSafeMode: "Il CSS personalizzato non è stato applicato, poiché la modalità sicura è attiva."
themeIsDefaultBecauseSafeMode: "Quando la modalità sicura è attiva, viene utilizzato il tema predefinito. Quando la modalità sicura viene disattivata, il tema torna a essere quello precedente."
thankYouForTestingBeta: "Grazie per la tua collaborazione nella verifica delle versioni beta!"
_order:
newest: "Prima i più recenti"
oldest: "Meno recenti prima"
@@ -1461,6 +1468,7 @@ _settings:
contentsUpdateFrequency_description2: "Quando la modalità è in tempo reale, arriveranno a prescindere."
showUrlPreview: "Mostra anteprima dell'URL"
showAvailableReactionsFirstInNote: "Mostra le reazioni disponibili in alto"
showPageTabBarBottom: "Visualizza le schede della pagina nella parte inferiore"
_chat:
showSenderName: "Mostra il nome del mittente"
sendOnEnter: "Invio spedisce"
@@ -1634,6 +1642,10 @@ _serverSettings:
fanoutTimelineDbFallback: "Elaborazione dati alternativa"
fanoutTimelineDbFallbackDescription: "Attivando l'elaborazione alternativa, verrà interrogato ulteriormente il database se la timeline non è nella cache. \nDisattivando, si può ridurre ulteriormente il carico del server, evitando l'elaborazione alternativa, ma limitando l'intervallo recuperabile delle timeline."
reactionsBufferingDescription: "Attivando questa opzione, puoi migliorare significativamente le prestazioni durante la creazione delle reazioni e ridurre il carico sul database. Tuttavia, aumenterà l'impiego di memoria Redis."
remoteNotesCleaning: "Pulizia automatica dei contenuti remoti"
remoteNotesCleaning_description: "Se abilitata, verranno periodicamente rimosse le vecchie Note remote senza relazioni, per ridurre il sovraccarico del sistema."
remoteNotesCleaningMaxProcessingDuration: "Durata massima del processo di pulizia"
remoteNotesCleaningExpiryDaysForEachNotes: "Periodo minimo di conservazione delle note"
inquiryUrl: "URL di contatto"
inquiryUrlDescription: "Specificare l'URL al modulo di contatto, oppure le informazioni con i dati di contatto dell'amministrazione."
openRegistration: "Registrazioni aperte"
@@ -1652,6 +1664,11 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor: "Visibilità dei contenuti generati dagli utenti ai non utenti"
userGeneratedContentsVisibilityForVisitor_description: "Questa funzionalità è utile per impedire che contenuti remoti inappropriati e difficili da moderare vengano inavvertitamente resi pubblici su Internet tramite il proprio server."
userGeneratedContentsVisibilityForVisitor_description2: "Esistono dei rischi nell'esporre incondizionatamente su internet tutto il contenuto del tuo server, incluso il contenuto remoto ricevuto da altri server. In particolare, occorre prestare attenzione, perché le persone non consapevoli della federazione potrebbero erroneamente credere che il contenuto remoto sia stato invece creato all'interno del proprio server."
restartServerSetupWizardConfirm_title: "Vuoi ripetere la procedura guidata di configurazione iniziale del server?"
restartServerSetupWizardConfirm_text: "Verranno ripristinate alcune tue impostazioni personalizzate."
entrancePageStyle: "Stile della pagina di ingresso"
showTimelineForVisitor: "Mostra la Timeline a visitatori non autenticati"
showActivitiesForVisitor: "Mostrare la propria attività"
_userGeneratedContentsVisibilityForVisitor:
all: "Tutto pubblico"
localOnly: "Pubblica solo contenuti locali, mantieni privati i contenuti remoti"
@@ -1988,6 +2005,7 @@ _role:
descriptionOfRateLimitFactor: "I rapporti più bassi sono meno restrittivi, quelli più alti lo sono di più."
canHideAds: "Nascondere i banner"
canSearchNotes: "Ricercare nelle Note"
canSearchUsers: "Può cercare profili"
canUseTranslator: "Tradurre le Note"
avatarDecorationLimit: "Numero massimo di decorazioni foto profilo installabili"
canImportAntennas: "Può importare Antenne"
@@ -2204,7 +2222,7 @@ _theme:
hashtag: "Hashtag"
mention: "Menzioni"
mentionMe: "Menzioni (di me)"
renote: "Renota"
renote: "Rinota"
modalBg: "Sfondo modale."
divider: "Interruzione di linea"
scrollbarHandle: "Maniglie della barra di scorrimento"
@@ -2260,6 +2278,7 @@ _time:
minute: "min"
hour: "ore"
day: "giorni"
month: "Mese"
_2fa:
alreadyRegistered: "La configurazione è stata già completata."
registerTOTP: "Registra una App di autenticazione a due fattori (2FA/MFA)"
@@ -2644,7 +2663,7 @@ _notification:
createToken: "È stato creato un token di accesso"
createTokenDescription: "In caso contrario, eliminare il token di accesso tramite ({text})."
_types:
all: "Tutto"
all: "Tutte"
note: "Nuove Note"
follow: "Follower"
mention: "Menzioni"
@@ -2652,7 +2671,7 @@ _notification:
renote: "Rinota"
quote: "Cita"
reaction: "Reazioni"
pollEnded: "Sondaggio chiuso."
pollEnded: "Sondaggio terminato"
receiveFollowRequest: "Richieste di follow in arrivo"
followRequestAccepted: "Richieste di follow accettate"
roleAssigned: "Ruolo concesso"
@@ -2660,7 +2679,7 @@ _notification:
achievementEarned: "Risultato raggiunto"
exportCompleted: "Esportazione completata"
login: "Accessi"
createToken: "Creare un token di accesso"
createToken: "Aggiunto un token di accesso"
test: "Notifiche di test"
app: "Notifiche da applicazioni"
_actions:
@@ -2752,56 +2771,56 @@ _abuseReport:
notifiedWebhook: "Webhook da usare"
deleteConfirm: "Vuoi davvero rimuovere il destinatario della notifica?"
_moderationLogTypes:
createRole: "Ruolo creato"
deleteRole: "Ruolo eliminato"
updateRole: "Ruolo aggiornato"
assignRole: "Ruolo assegnato"
unassignRole: "Ruolo disassegnato"
suspend: "Sospensione"
unsuspend: "Sospensione rimossa"
addCustomEmoji: "Emoji personalizzata aggiunta"
updateCustomEmoji: "Emoji personalizzata aggiornata"
deleteCustomEmoji: "Emoji personalizzata eliminata"
updateServerSettings: "Impostazioni del server aggiornate"
updateUserNote: "Promemoria di moderazione aggiornato"
deleteDriveFile: "File da Drive eliminato"
deleteNote: "Nota eliminata"
createGlobalAnnouncement: "Annuncio globale creato"
createUserAnnouncement: "Annuncio ai profili iscritti creato"
updateGlobalAnnouncement: "Annuncio globale aggiornato"
updateUserAnnouncement: "Annuncio ai profili iscritti aggiornato"
deleteGlobalAnnouncement: "Annuncio globale eliminato"
deleteUserAnnouncement: "Annuncio ai profili iscritti eliminato"
resetPassword: "Password azzerata"
suspendRemoteInstance: "Istanza remota sospesa"
unsuspendRemoteInstance: "Istanza remota riattivata"
updateRemoteInstanceNote: "Aggiornamento del promemoria di moderazione per il server remoto"
markSensitiveDriveFile: "File nel Drive segnato come esplicito"
unmarkSensitiveDriveFile: "File nel Drive segnato come non esplicito"
resolveAbuseReport: "Segnalazione risolta"
forwardAbuseReport: "Segnalazione inoltrata"
updateAbuseReportNote: "Ha aggiornato la segnalazione"
createInvitation: "Genera codice di invito"
createAd: "Banner creato"
deleteAd: "Banner eliminato"
updateAd: "Banner aggiornato"
createAvatarDecoration: "Creazione decorazione della foto profilo"
updateAvatarDecoration: "Aggiornamento decorazione foto profilo"
deleteAvatarDecoration: "Eliminazione decorazione della foto profilo"
unsetUserAvatar: "Rimossa foto profilo"
unsetUserBanner: "Rimossa intestazione profilo"
createSystemWebhook: "Crea un SystemWebhook"
updateSystemWebhook: "Modifica SystemWebhook"
deleteSystemWebhook: "Elimina SystemWebhook"
createRole: "Crea un Ruolo"
deleteRole: "Elimina un Ruolo"
updateRole: "Modifica un ruolo"
assignRole: "Assegna un Ruolo"
unassignRole: "Toglie un Ruolo al Profilo"
suspend: "Sospende"
unsuspend: "Solleva la sospensione"
addCustomEmoji: "Aggiunge Emoji personalizzata"
updateCustomEmoji: "Modifica Emoji personalizzata"
deleteCustomEmoji: "Elimina Emoji personalizzata"
updateServerSettings: "Modifica le impostazioni del server"
updateUserNote: "Modifica un promemoria di moderazione"
deleteDriveFile: "Elimina un file dal Drive"
deleteNote: "Elimina una Nota"
createGlobalAnnouncement: "Crea un annuncio globale"
createUserAnnouncement: "Crea un annuncio ai profili già iscritti"
updateGlobalAnnouncement: "Modifica un annuncio globale"
updateUserAnnouncement: "Modifica un annuncio ai profili già iscritti"
deleteGlobalAnnouncement: "Elimina un annuncio globale"
deleteUserAnnouncement: "Elimina un annuncio ai profili già iscritti"
resetPassword: "Azzera la password"
suspendRemoteInstance: "Sospende una istanza remota"
unsuspendRemoteInstance: "Riattiva una istanza remota"
updateRemoteInstanceNote: "Modifica il promemoria di moderazione per il server remoto"
markSensitiveDriveFile: "Aggiunge NSFW a un file nel Drive"
unmarkSensitiveDriveFile: "Toglie NSFW da un file nel Drive"
resolveAbuseReport: "Risolve una segnalazione"
forwardAbuseReport: "Inoltra una segnalazione"
updateAbuseReportNote: "Modifica una segnalazione"
createInvitation: "Genera un codice di invito"
createAd: "Aggiunge un Banner"
deleteAd: "Elimina un Banner"
updateAd: "Modifica un Banner"
createAvatarDecoration: "Crea una decorazione della foto profilo"
updateAvatarDecoration: "Modifica una decorazione della foto profilo"
deleteAvatarDecoration: "Elimina una decorazione della foto profilo"
unsetUserAvatar: "Toglie una foto profilo"
unsetUserBanner: "Toglie una immagine di intestazione profilo"
createSystemWebhook: "Aggiunge un System Webhook"
updateSystemWebhook: "Modifica un System Webhook"
deleteSystemWebhook: "Elimina un System Webhook"
createAbuseReportNotificationRecipient: "Crea destinatario per le notifiche di segnalazioni"
updateAbuseReportNotificationRecipient: "Aggiorna destinatario notifiche di segnalazioni"
deleteAbuseReportNotificationRecipient: "Elimina destinatario notifiche di segnalazioni"
deleteAccount: "Quando viene eliminato un profilo"
deletePage: "Pagina eliminata"
deleteFlash: "Play eliminato"
deleteGalleryPost: "Eliminazione pubblicazione nella Galleria"
deleteChatRoom: "Elimina chat"
updateProxyAccountDescription: "Aggiornata la descrizione del profilo proxy"
updateAbuseReportNotificationRecipient: "Modifica un destinatario per le notifiche di segnalazioni"
deleteAbuseReportNotificationRecipient: "Elimina un destinatario per le notifiche di segnalazioni"
deleteAccount: "Elimina un profilo"
deletePage: "Elimina una Pagina"
deleteFlash: "Elimina un Play"
deleteGalleryPost: "Elimina pubblicazione nella Galleria"
deleteChatRoom: "Elimina una Chat"
updateProxyAccountDescription: "Aggiorna la descrizione del profilo proxy"
_fileViewer:
title: "Dettagli del file"
type: "Tipo di file"
@@ -3062,6 +3081,7 @@ _bootErrors:
otherOption1: "Nelle impostazioni, cancellare le impostazioni del client e svuotare la cache"
otherOption2: "Avviare il client predefinito"
otherOption3: "Avviare lo strumento di riparazione"
otherOption4: "Avvia Misskey in modalità sicura"
_search:
searchScopeAll: "Tutte"
searchScopeLocal: "Locale"
@@ -3098,6 +3118,8 @@ _serverSetupWizard:
doYouConnectToFediverse_description1: "Collegandosi a una rete di server distribuiti, denominata Fediverso, potrai scambiare contenuti con altri server, tramite il protocollo di comunicazione ActivityPub."
doYouConnectToFediverse_description2: "Connettersi al Fediverso è anche detto \"federazione\"."
youCanConfigureMoreFederationSettingsLater: "Puoi svolgere la configurazione avanzata anche dopo. Ad esempio specificando quali server possono federarsi."
remoteContentsCleaning: "Pulizia automatica dei contenuti in arrivo"
remoteContentsCleaning_description: "Con la federazione funzionante, riceverai sempre più contenuti. Abilitando la pulizia automatica, i contenuti non referenziati e obsoleti verranno rimossi automaticamente dai tuoi server, risparmiando spazio di archiviazione."
adminInfo: "Informazioni sull'amministratore"
adminInfo_description: "Imposta le informazioni dell'amministratore utilizzate per accettare le richieste."
adminInfo_mustBeFilled: "Questa operazione è necessaria su un server aperto o se è attiva la federazione."
@@ -3150,10 +3172,10 @@ _watermarkEditor:
type: "Tipo"
image: "Immagini"
advanced: "Avanzato"
angle: "Angolo"
stripe: "Strisce"
stripeWidth: "Larghezza della linea"
stripeFrequency: "Il numero di linee"
angle: "Angolo"
polkadot: "A pallini"
checker: "revisore"
polkadotMainDotOpacity: "Opacità del punto principale"
@@ -3165,6 +3187,7 @@ _imageEffector:
title: "Effetto"
addEffect: "Aggiungi effetto"
discardChangesConfirm: "Scarta le modifiche ed esci?"
nothingToConfigure: "Nessuna impostazione configurabile."
_fxs:
chromaticAberration: "Aberrazione cromatica"
glitch: "Glitch"
@@ -3182,7 +3205,39 @@ _imageEffector:
checker: "revisore"
blockNoise: "Attenua rumore"
tearing: "Strappa immagine"
drafts: "Bozza"
_fxProps:
angle: "Angolo"
scale: "Dimensioni"
size: "Dimensioni"
color: "Colore"
opacity: "Opacità"
normalize: "Normalizza"
amount: "Quantità"
lightness: "Chiaro"
contrast: "Contrasto"
hue: "Tinta"
brightness: "Luminosità"
saturation: "Saturazione"
max: "Valore massimo"
min: "Valore minimo"
direction: "Orientamento"
phase: "Fasare"
frequency: "Frequenza"
strength: "Forza"
glitchChannelShift: "Glitch cambio canale"
seed: "Seme"
redComponent: "Rosso composito"
greenComponent: "Verde composito"
blueComponent: "Blu composito"
threshold: "Soglia"
centerX: "Centro orizzontale"
centerY: "Centro verticale"
zoomLinesSmoothing: "Levigatura"
zoomLinesSmoothingDescription: "Non si possono usare insieme la levigatura e la larghezza della linea centrale."
zoomLinesThreshold: "Limite delle linee zoom"
zoomLinesMaskSize: "Ampiezza del diametro"
zoomLinesBlack: "Bande nere"
drafts: "Bozze"
_drafts:
select: "Selezionare bozza"
cannotCreateDraftAnymore: "Hai superato il numero massimo di bozze ammissibili."
+112 -44
View File
@@ -302,7 +302,7 @@ uploadNFiles: "{n}個のファイルをアップロード"
explore: "みつける"
messageRead: "既読"
noMoreHistory: "これより過去の履歴はありません"
startChat: "チャットを始める"
startChat: "メッセージを送る"
nUsersRead: "{n}人が読みました"
agreeTo: "{0}に同意"
agree: "同意する"
@@ -477,7 +477,7 @@ notFoundDescription: "指定されたURLに該当するページはありませ
uploadFolder: "既定アップロード先"
markAsReadAllNotifications: "すべての通知を既読にする"
markAsReadAllUnreadNotes: "すべての投稿を既読にする"
markAsReadAllTalkMessages: "すべてのチャットを既読にする"
markAsReadAllTalkMessages: "すべてのダイレクトメッセージを既読にする"
help: "ヘルプ"
inputMessageHere: "ここにメッセージを入力"
close: "閉じる"
@@ -1054,6 +1054,7 @@ permissionDeniedError: "操作が拒否されました"
permissionDeniedErrorDescription: "このアカウントにはこの操作を行うための権限がありません。"
preset: "プリセット"
selectFromPresets: "プリセットから選択"
custom: "カスタム"
achievements: "実績"
gotInvalidResponseError: "サーバーの応答が無効です"
gotInvalidResponseErrorDescription: "サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから再度お試しください。"
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "スペースで区切るとAND指定になり、
hiddenTags: "非表示ハッシュタグ"
hiddenTagsDescription: "設定したタグをトレンドに表示させないようにします。改行で区切って複数設定できます。"
notesSearchNotAvailable: "ノート検索は利用できません。"
usersSearchNotAvailable: "ユーザー検索は利用できません。"
license: "ライセンス"
unfavoriteConfirm: "お気に入り解除しますか?"
myClips: "自分のクリップ"
@@ -1243,7 +1245,7 @@ releaseToRefresh: "離してリロード"
refreshing: "リロード中"
pullDownToRefresh: "引っ張ってリロード"
useGroupedNotifications: "通知をグルーピング"
signupPendingError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。"
emailVerificationFailedError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。"
cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要です。"
doReaction: "リアクションする"
code: "コード"
@@ -1341,6 +1343,8 @@ postForm: "投稿フォーム"
textCount: "文字数"
information: "情報"
chat: "チャット"
directMessage: "ダイレクトメッセージ"
directMessage_short: "メッセージ"
migrateOldSettings: "旧設定情報を移行"
migrateOldSettings_description: "通常これは自動で行われていますが、何らかの理由により上手く移行されなかった場合は手動で移行処理をトリガーできます。現在の設定情報は上書きされます。"
compress: "圧縮"
@@ -1374,53 +1378,56 @@ safeModeEnabled: "セーフモードが有効です"
pluginsAreDisabledBecauseSafeMode: "セーフモードが有効なため、プラグインはすべて無効化されています。"
customCssIsDisabledBecauseSafeMode: "セーフモードが有効なため、カスタムCSSは適用されていません。"
themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。"
thankYouForTestingBeta: "ベータ版の検証にご協力いただきありがとうございます!"
createUserSpecifiedNote: "ユーザー指定ノートを作成"
_order:
newest: "新しい順"
oldest: "古い順"
_chat:
messages: "メッセージ"
noMessagesYet: "まだメッセージはありません"
newMessage: "新しいメッセージ"
individualChat: "個人チャット"
individualChat_description: "特定ユーザーとの一対一のチャットができます。"
roomChat: "ルームチャット"
roomChat_description: "複数人でのチャットができます。\nまた、個人チャットを許可していないユーザーとでも、相手が受け入れればチャットができます。"
createRoom: "ルーを作成"
inviteUserToChat: "ユーザーを招待してチャットを始めましょう"
yourRooms: "作成したルー"
joiningRooms: "参加中のルー"
individualChat: "個"
individualChat_description: "特定ユーザーと個別にメッセージのやりとりができます。"
roomChat: "ルー"
roomChat_description: "複数人でメッセージのやりとりができます。\nまた、個別のメッセージを許可していないユーザーとでも、相手が受け入れればやりとりできます。"
createRoom: "ルーを作成"
inviteUserToChat: "ユーザーを招待してメッセージを送信しましょう"
yourRooms: "作成したルー"
joiningRooms: "参加中のルー"
invitations: "招待"
noInvitations: "招待はありません"
history: "履歴"
noHistory: "履歴はありません"
noRooms: "ルーはありません"
noRooms: "ルーはありません"
inviteUser: "ユーザーを招待"
sentInvitations: "送信した招待"
join: "参加"
ignore: "無視"
leave: "ルーから退出"
leave: "ルーから退出"
members: "メンバー"
searchMessages: "メッセージを検索"
home: "ホーム"
send: "送信"
newline: "改行"
muteThisRoom: "このルーをミュート"
deleteRoom: "ルーを削除"
chatNotAvailableForThisAccountOrServer: "このサーバー、またはこのアカウントでチャットは有効化されていません。"
chatIsReadOnlyForThisAccountOrServer: "このサーバー、またはこのアカウントでチャットは読み取り専用となっています。新たに書き込んだり、チャットルーを作成・参加したりすることはできません。"
chatNotAvailableInOtherAccount: "相手のアカウントでチャット機能が使えない状態になっています。"
cannotChatWithTheUser: "このユーザーとのチャットを開始できません"
cannotChatWithTheUser_description: "チャットが使えない状態になっているか、相手がチャットを開放していません。"
youAreNotAMemberOfThisRoomButInvited: "あなたはこのルーの参加者ではありませんが、招待が届いています。参加するには、招待を承認してください。"
muteThisRoom: "このルーをミュート"
deleteRoom: "ルーを削除"
chatNotAvailableForThisAccountOrServer: "このサーバー、またはこのアカウントでダイレクトメッセージは有効化されていません。"
chatIsReadOnlyForThisAccountOrServer: "このサーバー、またはこのアカウントでダイレクトメッセージは読み取り専用となっています。新たに書き込んだり、ルーを作成・参加したりすることはできません。"
chatNotAvailableInOtherAccount: "相手のアカウントでダイレクトメッセージが使えない状態になっています。"
cannotChatWithTheUser: "このユーザーとのダイレクトメッセージを開始できません"
cannotChatWithTheUser_description: "ダイレクトメッセージが使えない状態になっているか、相手がダイレクトメッセージを開放していません。"
youAreNotAMemberOfThisRoomButInvited: "あなたはこのルーの参加者ではありませんが、招待が届いています。参加するには、招待を承認してください。"
doYouAcceptInvitation: "招待を承認しますか?"
chatWithThisUser: "チャットする"
thisUserAllowsChatOnlyFromFollowers: "このユーザーはフォロワーからのみチャットを受け付けています。"
thisUserAllowsChatOnlyFromFollowing: "このユーザーは、このユーザーがフォローしているユーザーからのみチャットを受け付けています。"
thisUserAllowsChatOnlyFromMutualFollowing: "このユーザーは相互フォローのユーザーからのみチャットを受け付けています。"
thisUserNotAllowedChatAnyone: "このユーザーは誰からもチャットを受け付けていません。"
chatAllowedUsers: "チャットを許可する相手"
chatAllowedUsers_note: "自分からチャットメッセージを送った相手とはこの設定に関わらずチャットが可能です。"
chatWithThisUser: "ダイレクトメッセージ"
thisUserAllowsChatOnlyFromFollowers: "このユーザーはフォロワーからのみメッセージを受け付けています。"
thisUserAllowsChatOnlyFromFollowing: "このユーザーは、このユーザーがフォローしているユーザーからのみメッセージを受け付けています。"
thisUserAllowsChatOnlyFromMutualFollowing: "このユーザーは相互フォローのユーザーからのみメッセージを受け付けています。"
thisUserNotAllowedChatAnyone: "このユーザーは誰からもメッセージを受け付けていません。"
chatAllowedUsers: "メッセージを許可する相手"
chatAllowedUsers_note: "自分からメッセージを送った相手とはこの設定に関わらずメッセージの送受信が可能です。"
_chatAllowedUsers:
everyone: "誰でも"
followers: "自分のフォロワーのみ"
@@ -1657,7 +1664,7 @@ _serverSettings:
fanoutTimelineDbFallbackDescription: "有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。"
reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。"
remoteNotesCleaning: "リモート投稿の自動クリーニング"
remoteNotesCleaning_description: "有効にすると、参照されていない古いリモートの投稿を定期的にクリーンアップしてデータベースの肥大化を抑制します。"
remoteNotesCleaning_description: "有効にすると、一定期間経過したリモートの投稿を定期的にクリーンアップしてデータベースの肥大化を抑制します。"
remoteNotesCleaningMaxProcessingDuration: "最大クリーニング処理継続時間"
remoteNotesCleaningExpiryDaysForEachNotes: "最低ノート保持日数"
inquiryUrl: "問い合わせ先URL"
@@ -1680,6 +1687,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "サーバーで受信したリモートのコンテンツを含め、サーバー内の全てのコンテンツを無条件でインターネットに公開することはリスクが伴います。特に、分散型の特性を知らない閲覧者にとっては、リモートのコンテンツであってもサーバー内で作成されたコンテンツであると誤って認識してしまう可能性があるため、注意が必要です。"
restartServerSetupWizardConfirm_title: "サーバーの初期設定ウィザードをやり直しますか?"
restartServerSetupWizardConfirm_text: "現在の一部の設定はリセットされます。"
entrancePageStyle: "エントランスページのスタイル"
showTimelineForVisitor: "タイムラインを表示する"
showActivitiesForVisitor: "アクティビティを表示する"
_userGeneratedContentsVisibilityForVisitor:
all: "全て公開"
@@ -2020,6 +2030,7 @@ _role:
descriptionOfRateLimitFactor: "小さいほど制限が緩和され、大きいほど制限が強化されます。"
canHideAds: "広告の非表示"
canSearchNotes: "ノート検索の利用"
canSearchUsers: "ユーザー検索の利用"
canUseTranslator: "翻訳機能の利用"
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
canImportAntennas: "アンテナのインポートを許可"
@@ -2027,7 +2038,7 @@ _role:
canImportFollowing: "フォローのインポートを許可"
canImportMuting: "ミュートのインポートを許可"
canImportUserLists: "リストのインポートを許可"
chatAvailability: "チャットを許可"
chatAvailability: "ダイレクトメッセージを許可"
uploadableFileTypes: "アップロード可能なファイル種別"
uploadableFileTypes_caption: "MIMEタイプを指定します。改行で区切って複数指定できるほか、アスタリスク(*)でワイルドカード指定できます。(例: image/*)"
uploadableFileTypes_caption2: "ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。"
@@ -2274,7 +2285,7 @@ _theme:
buttonHoverBg: "ボタンの背景 (ホバー)"
inputBorder: "入力ボックスの縁取り"
badge: "バッジ"
messageBg: "チャットの背景"
messageBg: "メッセージの背景"
fgHighlighted: "強調された文字"
_sfx:
@@ -2282,7 +2293,7 @@ _sfx:
noteMy: "ノート(自分)"
notification: "通知"
reaction: "リアクション選択時"
chatMessage: "チャットのメッセージ"
chatMessage: "ダイレクトメッセージ"
_soundSettings:
driveFile: "ドライブの音声を使用"
@@ -2319,6 +2330,7 @@ _time:
minute: "分"
hour: "時間"
day: "日"
month: "ヶ月"
_2fa:
alreadyRegistered: "既に設定は完了しています。"
@@ -2361,8 +2373,8 @@ _permissions:
"write:favorites": "お気に入りを操作する"
"read:following": "フォローの情報を見る"
"write:following": "フォロー・フォロー解除する"
"read:messaging": "チャットを見る"
"write:messaging": "チャットを操作する"
"read:messaging": "ダイレクトメッセージを見る"
"write:messaging": "ダイレクトメッセージを操作する"
"read:mutes": "ミュートを見る"
"write:mutes": "ミュートを操作する"
"write:notes": "ノートを作成・削除する"
@@ -2435,8 +2447,8 @@ _permissions:
"read:clip-favorite": "クリップのいいねを見る"
"read:federation": "連合に関する情報を取得する"
"write:report-abuse": "違反を報告する"
"write:chat": "チャットを操作する"
"read:chat": "チャットを閲覧する"
"write:chat": "ダイレクトメッセージを操作する"
"read:chat": "ダイレクトメッセージを閲覧する"
_auth:
shareAccessTitle: "アプリへのアクセス許可"
@@ -2499,7 +2511,7 @@ _widgets:
chooseList: "リストを選択"
clicker: "クリッカー"
birthdayFollowings: "今日誕生日のユーザー"
chat: "チャット"
chat: "ダイレクトメッセージ"
_cw:
hide: "隠す"
@@ -2706,7 +2718,7 @@ _notification:
newNote: "新しい投稿"
unreadAntennaNote: "アンテナ {name}"
roleAssigned: "ロールが付与されました"
chatRoomInvitationReceived: "チャットルーへ招待されました"
chatRoomInvitationReceived: "ダイレクトメッセージのグルーへ招待されました"
emptyPushNotificationMessage: "プッシュ通知の更新をしました"
achievementEarned: "実績を獲得"
testNotification: "通知テスト"
@@ -2736,7 +2748,7 @@ _notification:
receiveFollowRequest: "フォロー申請を受け取った"
followRequestAccepted: "フォローが受理された"
roleAssigned: "ロールが付与された"
chatRoomInvitationReceived: "チャットルーへ招待された"
chatRoomInvitationReceived: "ダイレクトメッセージのグルーへ招待された"
achievementEarned: "実績の獲得"
exportCompleted: "エクスポートが完了した"
login: "ログイン"
@@ -2786,7 +2798,7 @@ _deck:
mentions: "メンション"
direct: "指名"
roleTimeline: "ロールタイムライン"
chat: "チャット"
chat: "ダイレクトメッセージ"
_dialog:
charactersExceeded: "最大文字数を超えています! 現在 {current} / 制限 {max}"
@@ -2889,7 +2901,7 @@ _moderationLogTypes:
deletePage: "ページを削除"
deleteFlash: "Playを削除"
deleteGalleryPost: "ギャラリーの投稿を削除"
deleteChatRoom: "チャットルーを削除"
deleteChatRoom: "ダイレクトメッセージのグルーを削除"
updateProxyAccountDescription: "プロキシアカウントの説明を更新"
_fileViewer:
@@ -3208,8 +3220,8 @@ _serverSetupWizard:
doYouConnectToFediverse_description1: "分散型サーバーで構成されるネットワーク(Fediverse)に接続すると、他のサーバーと相互にコンテンツのやり取りが可能です。"
doYouConnectToFediverse_description2: "Fediverseと接続することは「連合」とも呼ばれます。"
youCanConfigureMoreFederationSettingsLater: "連合可能なサーバーの指定など、高度な設定も後ほど可能です。"
remoteContentsCleaning: "受信コンテンツの自動クリーニング"
remoteContentsCleaning_description: "連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、参照されていない古くなったコンテンツを自動でサーバーから削除し、ストレージを節約できます。"
remoteContentsCleaning: "リモートコンテンツの自動クリーニング"
remoteContentsCleaning_description: "連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、一定期間経過したリモートコンテンツを自動でサーバーから削除し、ストレージを節約できます。"
adminInfo: "管理者情報"
adminInfo_description: "問い合わせを受け付けるために使用される管理者情報を設定します。"
adminInfo_mustBeFilled: "オープンサーバー、または連合がオンの場合は必ず入力が必要です。"
@@ -3263,14 +3275,16 @@ _watermarkEditor:
opacity: "不透明度"
scale: "サイズ"
text: "テキスト"
qr: "二次元コード"
position: "位置"
margin: "マージン"
type: "タイプ"
image: "画像"
advanced: "高度"
angle: "角度"
stripe: "ストライプ"
stripeWidth: "ラインの幅"
stripeFrequency: "ラインの数"
angle: "角度"
polkadot: "ポルカドット"
checker: "チェッカー"
polkadotMainDotOpacity: "メインドットの不透明度"
@@ -3278,11 +3292,13 @@ _watermarkEditor:
polkadotSubDotOpacity: "サブドットの不透明度"
polkadotSubDotRadius: "サブドットの大きさ"
polkadotSubDotDivisions: "サブドットの数"
leaveBlankToAccountUrl: "空欄にするとアカウントのURLになります"
_imageEffector:
title: "エフェクト"
addEffect: "エフェクトを追加"
discardChangesConfirm: "変更を破棄して終了しますか?"
nothingToConfigure: "設定項目はありません"
_fxs:
chromaticAberration: "色収差"
@@ -3301,6 +3317,41 @@ _imageEffector:
checker: "チェッカー"
blockNoise: "ブロックノイズ"
tearing: "ティアリング"
fillSquare: "塗りつぶし(四角)"
_fxProps:
angle: "角度"
scale: "サイズ"
size: "サイズ"
offset: "位置"
color: "色"
opacity: "不透明度"
normalize: "正規化"
amount: "量"
lightness: "明るさ"
contrast: "コントラスト"
hue: "色相"
brightness: "輝度"
saturation: "彩度"
max: "最大値"
min: "最小値"
direction: "方向"
phase: "位相"
frequency: "頻度"
strength: "強さ"
glitchChannelShift: "ズレ"
seed: "シード値"
redComponent: "赤色成分"
greenComponent: "緑色成分"
blueComponent: "青色成分"
threshold: "しきい値"
centerX: "中心X"
centerY: "中心Y"
zoomLinesSmoothing: "スムージング"
zoomLinesSmoothingDescription: "スムージングと集中線の幅の設定は併用できません。"
zoomLinesThreshold: "集中線の幅"
zoomLinesMaskSize: "中心径"
zoomLinesBlack: "黒色にする"
drafts: "下書き"
_drafts:
@@ -3317,3 +3368,20 @@ _drafts:
restoreFromDraft: "下書きから復元"
restore: "復元"
listDrafts: "下書き一覧"
qr: "二次元コード"
_qr:
showTabTitle: "表示"
readTabTitle: "読み取る"
shareTitle: "{name} {acct}"
shareText: "Fediverseで私をフォローしてください!"
chooseCamera: "カメラを選択"
cannotToggleFlash: "ライト選択不可"
turnOnFlash: "ライトをオンにする"
turnOffFlash: "ライトをオフにする"
startQr: "コードリーダーを再開"
stopQr: "コードリーダーを停止"
noQrCodeFound: "QRコードが見つかりません"
scanFile: "端末の画像をスキャン"
raw: "テキスト"
mfm: "MFM"
+7 -1
View File
@@ -1239,7 +1239,6 @@ releaseToRefresh: "離したらリロード"
refreshing: "リロードしとる"
pullDownToRefresh: "引っ張ってリロードするで"
useGroupedNotifications: "通知をグループ分けして出すで"
signupPendingError: "メアド確認してたらなんか変なことなったわ。リンクの期限切れてるかもしれん。"
cwNotationRequired: "「内容を隠す」んやったら注釈書かなアカンで。"
doReaction: "ツッコむで"
code: "コード"
@@ -3020,6 +3019,13 @@ _watermarkEditor:
angle: "角度"
_imageEffector:
discardChangesConfirm: "変更をせんで終わるか?"
_fxProps:
angle: "角度"
scale: "大きさ"
size: "大きさ"
color: "色"
opacity: "不透明度"
lightness: "明るさ"
_drafts:
cannotCreateDraftAnymore: "下書きはこれ以上は作れへんな。"
cannotCreateDraft: "この内容で下書きは作れへんな。"
+44 -2
View File
@@ -1054,6 +1054,7 @@ permissionDeniedError: "작업이 거부되었습니다"
permissionDeniedErrorDescription: "이 작업을 수행할 권한이 없습니다."
preset: "프리셋"
selectFromPresets: "프리셋에서 선택"
custom: "커스텀"
achievements: "도전 과제"
gotInvalidResponseError: "서버의 응답이 올바르지 않습니다"
gotInvalidResponseErrorDescription: " 서버가 다운되었거나 점검중일 가능성이 있습니다. 잠시후에 다시 시도해 주십시오."
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "공백으로 구분하면 AND 지정이 되며,
hiddenTags: "숨긴 해시태그"
hiddenTagsDescription: "설정한 태그를 트렌드에 표시하지 않도록 합니다. 줄 바꿈으로 하나씩 나눠서 설정할 수 있습니다."
notesSearchNotAvailable: "노트 검색을 이용하실 수 없습니다."
usersSearchNotAvailable: "유저 검색을 이용하실 수 없습니다."
license: "라이선스"
unfavoriteConfirm: "즐겨찾기를 해제하시겠습니까?"
myClips: "내 클립"
@@ -1243,7 +1245,7 @@ releaseToRefresh: "놓아서 새로고침"
refreshing: "새로고침 중"
pullDownToRefresh: "아래로 내려서 새로고침"
useGroupedNotifications: "알림을 그룹화하고 표시"
signupPendingError: "메일 주소 확인문제가 발생했습니다. 링크의 유효기간이 지났을 가능성이 있습니다."
emailVerificationFailedError: "메일 주소 확인에 실패했습니다. 확인에 필요한 URL의 유효기간이 지났을 가능성이 있습니다."
cwNotationRequired: "'내용을 숨기기'를 체크한 경우 주석을 써야 합니다."
doReaction: "리액션 추가"
code: "문자열"
@@ -1374,6 +1376,7 @@ safeModeEnabled: "세이프 모드가 활성화돼있습니다"
pluginsAreDisabledBecauseSafeMode: "세이프 모드가 활성화돼있기에 플러그인은 전부 비활성화됩니다."
customCssIsDisabledBecauseSafeMode: "세이프 모드가 활성화돼있기에 커스텀 CSS는 적용되지 않습니다."
themeIsDefaultBecauseSafeMode: "세이프 모드가 활성화돼있는 동안에는 기본 테마가 사용됩니다. 세이프 모드를 끄면 원래대로 돌아옵니다."
thankYouForTestingBeta: "베타 버전의 검증에 협력해 주셔서 감사합니다!"
_order:
newest: "최신 순"
oldest: "오래된 순"
@@ -1465,6 +1468,7 @@ _settings:
contentsUpdateFrequency_description2: "실시간 모드가 켜져 있을 때는 이 설정과 상관없이 실시간으로 콘텐츠가 업데이트됩니다."
showUrlPreview: "URL 미리보기 표시"
showAvailableReactionsFirstInNote: "이용 가능한 리액션을 선두로 표시"
showPageTabBarBottom: "페이지의 탭 바를 아래쪽에 표시"
_chat:
showSenderName: "발신자 이름 표시"
sendOnEnter: "엔터로 보내기"
@@ -1662,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "서버에서 받은 리모트 콘텐츠를 포함해 서버 내의 모든 콘텐츠를 무조건 인터넷에 공개하는 것에는 위험이 따릅니다. 특히, 분산형 특성에 대해 모르는 열람자에게는 리모트 콘텐츠여도 서버 내에서 작성된 콘텐츠라고 잘못 인식할 수 있기에 주의가 필요합니다."
restartServerSetupWizardConfirm_title: "서버의 초기 설정 위자드를 재시도하시겠습니까?"
restartServerSetupWizardConfirm_text: "현재 일부 설정은 리셋됩니다."
entrancePageStyle: "입구 페이지의 스타일"
showTimelineForVisitor: "타임라인 표시"
showActivitiesForVisitor: "액티비티 표시하기"
_userGeneratedContentsVisibilityForVisitor:
all: "모두 공개"
localOnly: "로컬 콘텐츠만 공개하고 리모트 콘텐츠는 비공개"
@@ -1998,6 +2005,7 @@ _role:
descriptionOfRateLimitFactor: "작을수록 제한이 완화되고, 클수록 제한이 강화됩니다."
canHideAds: "광고 숨기기"
canSearchNotes: "노트 검색 이용 가능 여부"
canSearchUsers: "유저 검색 이용"
canUseTranslator: "번역 기능의 사용"
avatarDecorationLimit: "아바타 장식의 최대 붙임 개수"
canImportAntennas: "안테나 가져오기 허용"
@@ -2270,6 +2278,7 @@ _time:
minute: "분"
hour: "시간"
day: "일"
month: "개월"
_2fa:
alreadyRegistered: "이미 설정이 완료되었습니다."
registerTOTP: "인증 앱 설정 시작"
@@ -3163,10 +3172,10 @@ _watermarkEditor:
type: "종류"
image: "이미지"
advanced: "고급"
angle: "각도"
stripe: "줄무늬"
stripeWidth: "라인의 폭"
stripeFrequency: "라인의 수"
angle: "각도"
polkadot: "물방울 무늬"
checker: "체크 무늬"
polkadotMainDotOpacity: "주요 물방울의 불투명도"
@@ -3178,6 +3187,7 @@ _imageEffector:
title: "이펙트"
addEffect: "이펙트를 추가"
discardChangesConfirm: "변경을 취소하고 종료하시겠습니까?"
nothingToConfigure: "설정 항목이 없습니다."
_fxs:
chromaticAberration: "색수차"
glitch: "글리치"
@@ -3195,6 +3205,38 @@ _imageEffector:
checker: "체크 무늬"
blockNoise: "노이즈 방지"
tearing: "티어링"
_fxProps:
angle: "각도"
scale: "크기"
size: "크기"
color: "색"
opacity: "불투명도"
normalize: "노멀라이즈"
amount: "양"
lightness: "밝음"
contrast: "대비"
hue: "색조"
brightness: "밝기"
saturation: "채도"
max: "최대 값"
min: "최소 값"
direction: "방향"
phase: "위상"
frequency: "빈도"
strength: "강도"
glitchChannelShift: "글리치"
seed: "시드 값"
redComponent: "빨간색 요소"
greenComponent: "녹색 요소"
blueComponent: "파란색 요소"
threshold: "한계 값"
centerX: "X축 중심"
centerY: "Y축 중심"
zoomLinesSmoothing: "다듬기"
zoomLinesSmoothingDescription: "다듬기와 집중선 폭 설정은 같이 쓸 수 없습니다."
zoomLinesThreshold: "집중선 폭"
zoomLinesMaskSize: "중앙 값"
zoomLinesBlack: "검은색으로 하기"
drafts: "초안"
_drafts:
select: "초안 선택"
+5
View File
@@ -742,3 +742,8 @@ _watermarkEditor:
text: "Tekst"
type: "Type"
image: "Bilder"
_imageEffector:
_fxProps:
scale: "Størrelse"
size: "Størrelse"
color: "Farge"
+7
View File
@@ -1593,3 +1593,10 @@ _watermarkEditor:
type: "Typ"
image: "Zdjęcia"
advanced: "Zaawansowane"
_imageEffector:
_fxProps:
scale: "Rozmiar"
size: "Rozmiar"
color: "Kolor"
opacity: "Przezroczystość"
lightness: "Rozjaśnij"
+8 -2
View File
@@ -1243,7 +1243,6 @@ releaseToRefresh: "Solte para atualizar"
refreshing: "Atualizando..."
pullDownToRefresh: "Puxe para baixo para atualizar"
useGroupedNotifications: "Agrupar notificações"
signupPendingError: "Houve um problema ao verificar o endereço de email. O link pode ter expirado."
cwNotationRequired: "Se \"Esconder conteúdo\" está habilitado, uma descrição deve ser adicionada."
doReaction: "Adicionar reação"
code: "Código"
@@ -3150,10 +3149,10 @@ _watermarkEditor:
type: "Tipo"
image: "imagem"
advanced: "Avançado"
angle: "Ângulo"
stripe: "Listras"
stripeWidth: "Largura da linha"
stripeFrequency: "Número de linhas"
angle: "Ângulo"
polkadot: "Bolinhas"
checker: "Xadrez"
polkadotMainDotOpacity: "Opacidade da bolinha principal"
@@ -3182,6 +3181,13 @@ _imageEffector:
checker: "Xadrez"
blockNoise: "Bloquear Ruído"
tearing: "Descontinuidade"
_fxProps:
angle: "Ângulo"
scale: "Tamanho"
size: "Tamanho"
color: "Cor"
opacity: "Opacidade"
lightness: "Esclarecer"
drafts: "Rascunhos"
_drafts:
select: "Selecionar Rascunho"
+4
View File
@@ -1400,3 +1400,7 @@ _watermarkEditor:
type: "Tip"
image: "Imagini"
advanced: "Avansat"
_imageEffector:
_fxProps:
scale: "Dimensiune"
size: "Dimensiune"
+25 -3
View File
@@ -1215,12 +1215,12 @@ privacyPolicyUrl: "Ссылка на Политику Конфиденциаль
tosAndPrivacyPolicy: "Условия использования и политика конфиденциальности"
avatarDecorations: "Украшения для аватара"
attach: "Прикрепить"
detachAll: "Убрать всё"
angle: "Угол"
flip: "Переворот"
showAvatarDecorations: "Показать украшения для аватара"
pullDownToRefresh: "Опустите что бы обновить"
useGroupedNotifications: "Отображать уведомления сгруппировано"
signupPendingError: "Возникла проблема с подтверждением вашего адреса электронной почты. Возможно, срок действия ссылки истёк."
cwNotationRequired: "Если включена опция «Скрыть содержимое», необходимо написать аннотацию."
doReaction: "Добавить реакцию"
code: "Код"
@@ -1254,7 +1254,7 @@ clipNoteLimitExceeded: "К этому клипу больше нельзя до
performance: "Производительность"
modified: "Изменено"
signinWithPasskey: "Войдите в систему, используя свой пароль"
unknownWebAuthnKey: "Не известный ключ "
unknownWebAuthnKey: "Неизвестный ключ"
passkeyVerificationFailed: "Ошибка проверка ключа доступа "
messageToFollower: "Сообщение подписчикам"
testCaptchaWarning: "Эта функция предназначена для тестирования CAPTCHA. <strong>Не использовать это в рабочей среде</strong>"
@@ -1269,8 +1269,11 @@ availableRoles: "Доступные роли"
federationDisabled: "Федерация отключена для этого сервера. Вы не можете взаимодействовать с пользователями на других серверах."
draft: "Черновик"
markAsSensitiveConfirm: "Отметить контент как чувствительный?"
preferences: "Основное"
resetToDefaultValue: "Сбросить настройки до стандартных"
syncBetweenDevices: "Синхронизировать между устройствами"
postForm: "Форма отправки"
textCount: "Количество символов"
information: "Описание"
inMinutes: "мин"
inDays: "сут"
@@ -1282,6 +1285,11 @@ _chat:
send: "Отправить"
_settings:
webhook: "Вебхук"
preferencesBanner: "Вы можете настроить общее поведение клиента по вашим предпочтениям"
timelineAndNote: "Лента и заметки"
_chat:
showSenderName: "Показывать имя отправителя"
sendOnEnter: "Использовать Enter для отправки"
_delivery:
stop: "Заморожено"
_type:
@@ -1530,7 +1538,7 @@ _achievements:
description: "Нажато здесь"
_justPlainLucky:
title: "Чистая удача"
description: "Может достаться с вероятностью 0,01% каждые 10 секунд."
description: "Может достаться с вероятностью 0,005% каждые 10 секунд."
_setNameToSyuilo:
title: "Комплекс бога"
description: "Установлено «syuilo» в качестве имени"
@@ -1558,6 +1566,12 @@ _achievements:
title: "Brain Diver"
description: "Опубликована ссылка на песню «Brain Diver»"
flavor: "Мисски-Мисски Ла-Ту-Ма"
_bubbleGameExplodingHead:
title: "🤯"
description: "Самый большой объект в Bubble game"
_bubbleGameDoubleExplodingHead:
title: "Двойной🤯"
description: "Два самых больших объекта в Bubble game одновременно!"
_role:
new: "Новая роль"
edit: "Изменить роль"
@@ -2257,4 +2271,12 @@ _watermarkEditor:
image: "Изображения"
advanced: "Для продвинутых"
angle: "Угол"
_imageEffector:
_fxProps:
angle: "Угол"
scale: "Размер"
size: "Размер"
color: "Цвет"
opacity: "Непрозрачность"
lightness: "Осветление"
drafts: "Черновик"
+7
View File
@@ -1459,3 +1459,10 @@ _watermarkEditor:
type: "Typ"
image: "Obrázky"
advanced: "Rozšírené"
_imageEffector:
_fxProps:
scale: "Veľkosť"
size: "Veľkosť"
color: "Farba"
opacity: "Priehľadnosť"
lightness: "Zosvetliť"
+5
View File
@@ -716,3 +716,8 @@ _search:
_watermarkEditor:
scale: "Storlek"
image: "Bilder"
_imageEffector:
_fxProps:
scale: "Storlek"
size: "Storlek"
color: "Färg"
+45 -2
View File
@@ -1054,6 +1054,7 @@ permissionDeniedError: "การดำเนินถูกปฏิเสธ"
permissionDeniedErrorDescription: "บัญชีนี้ไม่มีสิทธิ์อนุญาตในการดำเนินการนี้"
preset: "พรีเซ็ต"
selectFromPresets: "เลือกจากการพรีเซ็ต"
custom: "แบบกำหนดเอง"
achievements: "ความสำเร็จ"
gotInvalidResponseError: "การตอบสนองเซิร์ฟเวอร์ไม่ถูกต้อง"
gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะกำลังอยู่ในระหว่างปรับปรุง กรุณาลองใหม่อีกครั้งในภายหลังนะคะ"
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "ถ้าแยกด้วยเว้นวร
hiddenTags: "แฮชแท็กที่ซ่อนอยู่"
hiddenTagsDescription: "เลือกแท็กที่จะไม่แสดงในรายการเทรนด์ สามารถลงทะเบียนหลายแท็กได้โดยขึ้นบรรทัดใหม่"
notesSearchNotAvailable: "การค้นหาโน้ตไม่พร้อมใช้งาน"
usersSearchNotAvailable: "การค้นหาผู้ใช้ไม่พร้อมใช้งาน"
license: "ใบอนุญาต"
unfavoriteConfirm: "ลบออกจากรายการโปรดแน่ใจหรอ?"
myClips: "คลิปของฉัน"
@@ -1243,7 +1245,6 @@ releaseToRefresh: "ปล่อยเพื่อรีเฟรช"
refreshing: "กำลังรีเฟรช..."
pullDownToRefresh: "ดึงลงเพื่อรีเฟรช"
useGroupedNotifications: "แสดงผลการแจ้งเตือนแบบกลุ่มแล้ว"
signupPendingError: "มีปัญหาในการตรวจสอบที่อยู่อีเมลลิงก์อาจหมดอายุแล้ว"
cwNotationRequired: "หากเปิดใช้งาน “ซ่อนเนื้อหา” จะต้องระบุคำอธิบาย"
doReaction: "เพิ่มรีแอคชั่น"
code: "โค้ด"
@@ -1370,6 +1371,11 @@ defaultImageCompressionLevel: "ความละเอียดเริ่ม
defaultImageCompressionLevel_description: "หากตั้งค่าต่ำ จะรักษาคุณภาพภาพได้ดีขึ้นแต่ขนาดไฟล์จะเพิ่มขึ้น<br>หากตั้งค่าสูง จะลดขนาดไฟล์ได้ แต่คุณภาพภาพจะลดลง"
inMinutes: "นาที"
inDays: "วัน"
safeModeEnabled: "โหมดปลอดภัยถูกเปิดใช้งาน"
pluginsAreDisabledBecauseSafeMode: "เนื่องจากโหมดปลอดภัยถูกเปิดใช้งาน ปลั๊กอินทั้งหมดจึงถูกปิดใช้งาน"
customCssIsDisabledBecauseSafeMode: "เนื่องจากโหมดปลอดภัยถูกเปิดใช้งาน CSS แบบกำหนดเองจึงไม่ได้ถูกนำมาใช้"
themeIsDefaultBecauseSafeMode: "ในระหว่างที่โหมดปลอดภัยถูกเปิดใช้งาน จะใช้ธีมเริ่มต้น เมื่อปิดโหมดปลอดภัยจะกลับคืนดังเดิม"
thankYouForTestingBeta: "ขอบคุณที่ให้ความร่วมมือในการทดสอบเวอร์ชันเบต้า!"
_order:
newest: "เรียงจากใหม่ไปเก่า"
oldest: "เรียงจากเก่าไปใหม่"
@@ -1461,6 +1467,7 @@ _settings:
contentsUpdateFrequency_description2: "เมื่อโหมดเรียลไทม์เปิดอยู่ เนื้อหาจะอัปเดตแบบเรียลไทม์โดยไม่ขึ้นกับการตั้งค่านี้"
showUrlPreview: "แสดงตัวอย่าง URL"
showAvailableReactionsFirstInNote: "แสดงรีแอคชั่นที่ใช้ได้ไว้หน้าสุด"
showPageTabBarBottom: "แสดงแท็บบาร์ของเพจที่ด้านล่าง"
_chat:
showSenderName: "แสดงชื่อผู้ส่ง"
sendOnEnter: "กด Enter เพื่อส่ง"
@@ -1994,6 +2001,7 @@ _role:
descriptionOfRateLimitFactor: "ยิ่งตัวเลขน้อยก็ยิ่งจำกัดน้อย ยิ่งมากก็ยิ่งเข้มงวดมากขึ้น"
canHideAds: "ซ่อนโฆษณา"
canSearchNotes: "การใช้การค้นหาโน้ต"
canSearchUsers: "ค้นหาผู้ใช้"
canUseTranslator: "การใช้งานแปล"
avatarDecorationLimit: "จำนวนของตกแต่งไอคอนสูงสุดที่สามารถติดตั้งได้"
canImportAntennas: "อนุญาตให้นำเข้าเสาอากาศ"
@@ -2266,6 +2274,7 @@ _time:
minute: "นาที"
hour: "ชั่วโมง"
day: "วัน"
month: "เดือน"
_2fa:
alreadyRegistered: "คุณได้ลงทะเบียนอุปกรณ์ยืนยันตัวตนแบบ 2 ชั้นแล้ว"
registerTOTP: "ลงทะเบียนแอพตัวตรวจสอบสิทธิ์"
@@ -3068,6 +3077,7 @@ _bootErrors:
otherOption1: "ลบการตั้งค่าและแคชของไคลเอนต์"
otherOption2: "เริ่มใช้งานไคลเอนต์แบบง่าย"
otherOption3: "เปิดเครื่องมือซ่อมแซม"
otherOption4: "เริ่มทำงาน Misskey ในโหมดปลอดภัย"
_search:
searchScopeAll: "ทั้งหมด"
searchScopeLocal: "ท้องถิ่น"
@@ -3158,10 +3168,10 @@ _watermarkEditor:
type: "รูปแบบ"
image: "รูปภาพ"
advanced: "ขั้นสูง"
angle: "แองเกิล"
stripe: "ริ้ว"
stripeWidth: "ความกว้างเส้น"
stripeFrequency: "จำนวนเส้น"
angle: "แองเกิล"
polkadot: "ลายจุด"
checker: "ช่องตาราง"
polkadotMainDotOpacity: "ความทึบของจุดหลัก"
@@ -3173,6 +3183,7 @@ _imageEffector:
title: "เอฟเฟกต์"
addEffect: "เพิ่มเอฟเฟกต์"
discardChangesConfirm: "ต้องการทิ้งการเปลี่ยนแปลงแล้วออกหรือไม่?"
nothingToConfigure: "ไม่มีอะไรให้ตั้งค่า"
_fxs:
chromaticAberration: "ความคลาดสี"
glitch: "กลิตช์"
@@ -3190,6 +3201,38 @@ _imageEffector:
checker: "ช่องตาราง"
blockNoise: "บล็อกที่มีการรบกวน"
tearing: "ฉีกขาด"
_fxProps:
angle: "แองเกิล"
scale: "ขนาด"
size: "ขนาด"
color: "สี"
opacity: "ความทึบแสง"
normalize: "นอร์มัลไลซ์"
amount: "จำนวน"
lightness: "สว่าง"
contrast: "คอนทราสต์"
hue: "HUE"
brightness: "ความสว่าง"
saturation: "ความอิ่มตัว"
max: "สูงสุด"
min: "ต่ำสุด"
direction: "ทิศทาง"
phase: "ระยะ"
frequency: "ความถี่"
strength: "ความแรง"
glitchChannelShift: "ความเคลื่อน"
seed: "ซีด"
redComponent: "ส่วนสีแดง"
greenComponent: "ส่วนสีเขียว"
blueComponent: "ส่วนสีน้ำเงิน"
threshold: "เทรชโฮลด์"
centerX: "กลาง X"
centerY: "กลาง Y"
zoomLinesSmoothing: "ทำให้สมูธ"
zoomLinesSmoothingDescription: "ตั้งให้สมูธไม่สามารถใช้ร่วมกับตั้งความกว้างเส้นรวมศูนย์ได้"
zoomLinesThreshold: "ความกว้างเส้นรวมศูนย์"
zoomLinesMaskSize: "ขนาดพื้นที่ตรงกลาง"
zoomLinesBlack: "ทำให้ดำ"
drafts: "ร่าง"
_drafts:
select: "เลือกฉบับร่าง"
+570 -528
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -1648,3 +1648,10 @@ _watermarkEditor:
type: "Тип"
image: "Зображення"
advanced: "Розширені"
_imageEffector:
_fxProps:
scale: "Розмір"
size: "Розмір"
color: "Колір"
opacity: "Непрозорість"
lightness: "Яскравість"
+4
View File
@@ -1102,3 +1102,7 @@ _watermarkEditor:
type: "turi"
image: "Rasmlar"
advanced: "Murakkab"
_imageEffector:
_fxProps:
color: "Rang"
lightness: "Yoritish"
+8 -1
View File
@@ -1196,7 +1196,6 @@ showAvatarDecorations: "Hiển thị trang trí ảnh đại diện"
releaseToRefresh: "Thả để làm mới"
refreshing: "Đang làm mới"
pullDownToRefresh: "Kéo xuống để làm mới"
signupPendingError: "Đã xảy ra sự cố khi xác minh địa chỉ email của bạn. Liên kết có thể đã hết hạn."
cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
decorate: "Trang trí"
lastNDays: "{n} ngày trước"
@@ -2091,3 +2090,11 @@ _watermarkEditor:
image: "Hình ảnh"
advanced: "Nâng cao"
angle: "Góc"
_imageEffector:
_fxProps:
angle: "Góc"
scale: "Kích thước"
size: "Kích thước"
color: "Màu sắc"
opacity: "Độ trong suốt"
lightness: "Độ sáng"
+44 -2
View File
@@ -1054,6 +1054,7 @@ permissionDeniedError: "操作被拒绝"
permissionDeniedErrorDescription: "本账户没有执行该操作的权限。"
preset: "预设值"
selectFromPresets: "从预设值中选择"
custom: "自定义"
achievements: "成就"
gotInvalidResponseError: "服务器无应答"
gotInvalidResponseErrorDescription: "您的网络连接可能出现了问题, 或是远程服务器暂时不可用. 请稍后重试。"
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "AND 条件用空格分隔,正则表达式用斜
hiddenTags: "隐藏标签"
hiddenTagsDescription: "设定的标签将不会在时间线上显示。可使用换行来设置多个标签。"
notesSearchNotAvailable: "帖子检索不可用"
usersSearchNotAvailable: "用户检索不可用"
license: "许可信息"
unfavoriteConfirm: "确定要取消收藏吗?"
myClips: "我的便签"
@@ -1243,7 +1245,7 @@ releaseToRefresh: "松开以刷新"
refreshing: "刷新中"
pullDownToRefresh: "下拉以刷新"
useGroupedNotifications: "分组显示通知"
signupPendingError: "确认电子邮件时出现错误。链接可能已过期。"
emailVerificationFailedError: "确认电子邮件时出现错误。链接可能已过期。"
cwNotationRequired: "在启用「隐藏内容」时必须输入注释"
doReaction: "回应"
code: "代码"
@@ -1374,6 +1376,7 @@ safeModeEnabled: "已启用安全模式"
pluginsAreDisabledBecauseSafeMode: "因启用了安全模式,所有插件均已被禁用。"
customCssIsDisabledBecauseSafeMode: "因启用了安全模式,无法应用自定义 CSS。"
themeIsDefaultBecauseSafeMode: "启用安全模式时将使用默认主题。关闭安全模式后将还原。"
thankYouForTestingBeta: "感谢您协助测试 beta 版!"
_order:
newest: "从新到旧"
oldest: "从旧到新"
@@ -1465,6 +1468,7 @@ _settings:
contentsUpdateFrequency_description2: "当实时模式开启时,无论此设置如何,内容都会实时更新。"
showUrlPreview: "显示 URL 预览"
showAvailableReactionsFirstInNote: "在顶部显示可用的回应"
showPageTabBarBottom: "在下方显示页面标签栏"
_chat:
showSenderName: "显示发送者的名字"
sendOnEnter: "回车键发送"
@@ -1662,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "包含服务器接收到的远程内容在内,无条件将服务器上的所有内容公开在互联网上存在风险。特别是对去中心化的特性不是很了解的访问者有可能将远程服务器上的内容误认为是在此服务器内生成的,需要特别留意。"
restartServerSetupWizardConfirm_title: "要重新开始服务器初始设定向导吗?"
restartServerSetupWizardConfirm_text: "现有的部分设定将重置。"
entrancePageStyle: "入口页面样式"
showTimelineForVisitor: "显示时间线"
showActivitiesForVisitor: "显示活动"
_userGeneratedContentsVisibilityForVisitor:
all: "全部公开"
localOnly: "仅公开本地内容,隐藏远程内容"
@@ -1998,6 +2005,7 @@ _role:
descriptionOfRateLimitFactor: "值越小限制越少,值越大限制越多。"
canHideAds: "可以隐藏广告"
canSearchNotes: "是否可以搜索帖子"
canSearchUsers: "使用用户检索"
canUseTranslator: "使用翻译功能"
avatarDecorationLimit: "可添加头像挂件的最大个数"
canImportAntennas: "允许导入天线"
@@ -2270,6 +2278,7 @@ _time:
minute: "分"
hour: "小时"
day: "日"
month: "个月"
_2fa:
alreadyRegistered: "此设备已被注册"
registerTOTP: "开始设置验证器"
@@ -3163,10 +3172,10 @@ _watermarkEditor:
type: "类型"
image: "图片"
advanced: "高级"
angle: "角度"
stripe: "条纹"
stripeWidth: "线条宽度"
stripeFrequency: "线条数量"
angle: "角度"
polkadot: "波点"
checker: "检查"
polkadotMainDotOpacity: "主波点的不透明度"
@@ -3178,6 +3187,7 @@ _imageEffector:
title: "效果"
addEffect: "添加效果"
discardChangesConfirm: "丢弃当前设置并退出?"
nothingToConfigure: "还没有设置"
_fxs:
chromaticAberration: "色差"
glitch: "故障"
@@ -3195,6 +3205,38 @@ _imageEffector:
checker: "检查"
blockNoise: "块状噪点"
tearing: "撕裂"
_fxProps:
angle: "角度"
scale: "大小"
size: "大小"
color: "颜色"
opacity: "不透明度"
normalize: "标准化"
amount: "数量"
lightness: "浅色"
contrast: "对比度"
hue: "色调"
brightness: "亮度"
saturation: "饱和度"
max: "最大值"
min: "最小值"
direction: "方向"
phase: "相位"
frequency: "频率"
strength: "强度"
glitchChannelShift: "错位"
seed: "种子"
redComponent: "红色成分"
greenComponent: "绿色成分"
blueComponent: "蓝色成分"
threshold: "阈值"
centerX: "中心 X "
centerY: "中心 Y"
zoomLinesSmoothing: "平滑"
zoomLinesSmoothingDescription: "平滑和集中线宽度设置不能同时使用。"
zoomLinesThreshold: "集中线宽度"
zoomLinesMaskSize: "中心直径"
zoomLinesBlack: "变成黑色"
drafts: "草稿"
_drafts:
select: "选择草稿"
+46 -4
View File
@@ -1054,6 +1054,7 @@ permissionDeniedError: "操作被拒絕"
permissionDeniedErrorDescription: "此帳戶沒有執行這個操作的權限。"
preset: "預設值"
selectFromPresets: "從預設值中選擇"
custom: "自訂"
achievements: "成就"
gotInvalidResponseError: "伺服器的回應無效"
gotInvalidResponseErrorDescription: "伺服器可能已關閉或者在維護中,請稍後再試。"
@@ -1092,6 +1093,7 @@ prohibitedWordsDescription2: "空格代表「以及」(AND),斜線包圍
hiddenTags: "隱藏標籤"
hiddenTagsDescription: "設定的標籤不會在趨勢中顯示,換行可以設定多個標籤。"
notesSearchNotAvailable: "無法使用搜尋貼文功能。"
usersSearchNotAvailable: "無法使用使用者搜尋功能。"
license: "授權"
unfavoriteConfirm: "要取消收錄我的最愛嗎?"
myClips: "我的摘錄"
@@ -1243,7 +1245,7 @@ releaseToRefresh: "放開以更新內容"
refreshing: "載入更新中"
pullDownToRefresh: "往下拉來更新內容"
useGroupedNotifications: "分組顯示通知訊息"
signupPendingError: "驗證您的電子郵件地址時出現問題。連結可能已過期。"
emailVerificationFailedError: "驗證您的電子郵件地址時出現問題。連結可能已過期。"
cwNotationRequired: "如果開啟「隱藏內容」,則需要註解說明。"
doReaction: "做出反應"
code: "程式碼"
@@ -1373,7 +1375,8 @@ inDays: "日"
safeModeEnabled: "啟用安全模式"
pluginsAreDisabledBecauseSafeMode: "由於啟用安全模式,所有的外掛都被停用。"
customCssIsDisabledBecauseSafeMode: "由於啟用安全模式,所有的客製 CSS 都被停用。"
themeIsDefaultBecauseSafeMode: "啟用安全模式將使用預設主題關閉安全模式時將恢復預設主題。"
themeIsDefaultBecauseSafeMode: "安全模式啟用期間將使用預設主題關閉安全模式後會恢復原本的設定。"
thankYouForTestingBeta: "感謝您協助驗證 beta 版!"
_order:
newest: "最新的在前"
oldest: "最舊的在前"
@@ -1465,6 +1468,7 @@ _settings:
contentsUpdateFrequency_description2: "當即時模式開啟時,不論此設定為何,內容都會即時更新。"
showUrlPreview: "顯示網址預覽"
showAvailableReactionsFirstInNote: "將可用的反應顯示在頂部"
showPageTabBarBottom: "在底部顯示頁面的標籤列"
_chat:
showSenderName: "顯示發送者的名稱"
sendOnEnter: "按下 Enter 發送訊息"
@@ -1549,7 +1553,7 @@ _initialAccountSetting:
theseSettingsCanEditLater: "這裡的設定可以在之後變更。"
youCanEditMoreSettingsInSettingsPageLater: "除此之外,還可以在「設定」頁面進行各種設定。之後請確認看看。"
followUsers: "為了構築時間軸,試著追隨您感興趣的使用者吧。"
pushNotificationDescription: "啟用推送通知後,就可以在裝置上接收來自{name}的通知了。"
pushNotificationDescription: "啟用推送通知後,就可以在裝置上接收來自 {name} 的通知了。"
initialAccountSettingCompleted: "初始設定完成了!"
haveFun: "盡情享受{name}吧!"
youCanContinueTutorial: "您可以繼續學習如何使用{name}(Misskey),也可以就此打住,立即開始使用。"
@@ -1662,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "包括伺服器接收到的遠端內容在內,無條件地將伺服器內所有內容公開到網際網路上是具有風險的。特別是對於不了解分散式架構特性的瀏覽者來說,他們可能會誤以為這些遠端內容是由該伺服器所創建的,因此需要特別留意。"
restartServerSetupWizardConfirm_title: "要重新執行伺服器的初始設定精靈嗎?"
restartServerSetupWizardConfirm_text: "當前的部分設定將會被重設。"
entrancePageStyle: "入口頁面的樣式"
showTimelineForVisitor: "顯示時間軸"
showActivitiesForVisitor: "顯示活動"
_userGeneratedContentsVisibilityForVisitor:
all: "全部公開\n"
localOnly: "僅公開本地內容,遠端內容則不公開\n"
@@ -1998,6 +2005,7 @@ _role:
descriptionOfRateLimitFactor: "值越小限制越少,值越大限制越多。"
canHideAds: "不顯示廣告"
canSearchNotes: "可否搜尋貼文"
canSearchUsers: "可使用使用者搜尋功能"
canUseTranslator: "使用翻譯功能"
avatarDecorationLimit: "頭像可掛上的最大裝飾數量"
canImportAntennas: "允許匯入天線"
@@ -2270,6 +2278,7 @@ _time:
minute: "分鐘"
hour: "小時"
day: "日"
month: "個月"
_2fa:
alreadyRegistered: "此裝置已被註冊過了"
registerTOTP: "開始設定驗證應用程式"
@@ -3163,10 +3172,10 @@ _watermarkEditor:
type: "類型"
image: "圖片"
advanced: "進階"
angle: "角度"
stripe: "條紋"
stripeWidth: "線條寬度"
stripeFrequency: "線條數量"
angle: "角度"
polkadot: "波卡圓點"
checker: "棋盤格"
polkadotMainDotOpacity: "主圓點的不透明度"
@@ -3178,6 +3187,7 @@ _imageEffector:
title: "特效"
addEffect: "新增特效"
discardChangesConfirm: "捨棄更改並退出嗎?"
nothingToConfigure: "無可設定的項目"
_fxs:
chromaticAberration: "色差"
glitch: "異常雜訊效果"
@@ -3195,6 +3205,38 @@ _imageEffector:
checker: "棋盤格"
blockNoise: "阻擋雜訊"
tearing: "撕裂"
_fxProps:
angle: "角度"
scale: "大小"
size: "大小"
color: "顏色"
opacity: "透明度"
normalize: "正規化"
amount: "數量"
lightness: "亮度"
contrast: "對比度"
hue: "色相"
brightness: "亮度"
saturation: "彩度"
max: "最大值"
min: "最小值"
direction: "方向"
phase: "相位"
frequency: "頻率"
strength: "強度"
glitchChannelShift: "偏移"
seed: "種子值"
redComponent: "紅色成分"
greenComponent: "綠色成分"
blueComponent: "青色成分"
threshold: "閾值"
centerX: "X中心座標"
centerY: "Y中心座標"
zoomLinesSmoothing: "平滑化"
zoomLinesSmoothingDescription: "平滑化與集中線寬度設定不能同時使用。"
zoomLinesThreshold: "集中線的寬度"
zoomLinesMaskSize: "中心直徑"
zoomLinesBlack: "變成黑色"
drafts: "草稿\n"
_drafts:
select: "選擇草槁"
+15 -13
View File
@@ -1,12 +1,12 @@
{
"name": "misskey",
"version": "2025.8.0-alpha.5",
"version": "2025.9.1-alpha.0",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/misskey-dev/misskey.git"
},
"packageManager": "pnpm@10.13.1",
"packageManager": "pnpm@10.15.1",
"workspaces": [
"packages/frontend-shared",
"packages/frontend",
@@ -27,6 +27,7 @@
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
"start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
"cli": "cd packages/backend && pnpm cli",
"init": "pnpm migrate",
"migrate": "cd packages/backend && pnpm migrate",
"revert": "cd packages/backend && pnpm revert",
@@ -52,8 +53,8 @@
"lodash": "4.17.21"
},
"dependencies": {
"cssnano": "7.1.0",
"esbuild": "0.25.6",
"cssnano": "7.1.1",
"esbuild": "0.25.9",
"execa": "9.6.0",
"fast-glob": "3.3.3",
"glob": "11.0.3",
@@ -61,21 +62,22 @@
"js-yaml": "4.1.0",
"postcss": "8.5.6",
"tar": "7.4.3",
"terser": "5.43.1",
"typescript": "5.8.3"
"terser": "5.44.0",
"typescript": "5.9.2"
},
"devDependencies": {
"@misskey-dev/eslint-plugin": "2.1.0",
"@types/node": "22.16.4",
"@typescript-eslint/eslint-plugin": "8.37.0",
"@typescript-eslint/parser": "8.37.0",
"@types/js-yaml": "4.0.9",
"@types/node": "22.18.1",
"@typescript-eslint/eslint-plugin": "8.42.0",
"@typescript-eslint/parser": "8.42.0",
"cross-env": "7.0.3",
"cypress": "14.5.2",
"eslint": "9.31.0",
"cypress": "14.5.4",
"eslint": "9.35.0",
"globals": "16.3.0",
"ncp": "2.0.0",
"pnpm": "10.13.1",
"start-server-and-test": "2.0.12"
"pnpm": "10.15.1",
"start-server-and-test": "2.1.0"
},
"optionalDependencies": {
"@tensorflow/tfjs-core": "4.22.0"
@@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class PageCountInNote1755168347001 {
name = 'PageCountInNote1755168347001'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" ADD "pageCount" smallint NOT NULL DEFAULT '0'`);
// Update existing notes
// block_list CTE collects all page blocks on the pages including child blocks in the section blocks.
// The clipped_notes CTE counts how many distinct pages each note block is referenced in.
// Finally, we update the note table with the count of pages for each referenced note.
await queryRunner.query(`
WITH RECURSIVE block_list AS (
(
SELECT
page.id as page_id,
block as block
FROM page
CROSS JOIN LATERAL jsonb_array_elements(page.content) block
WHERE block->>'type' = 'note' OR block->>'type' = 'section'
)
UNION ALL
(
SELECT
block_list.page_id,
child_block AS block
FROM LATERAL (
SELECT page_id, block
FROM block_list
WHERE block_list.block->>'type' = 'section'
) block_list
CROSS JOIN LATERAL jsonb_array_elements(block_list.block->'children') child_block
WHERE child_block->>'type' = 'note' OR child_block->>'type' = 'section'
)
),
clipped_notes AS (
SELECT
(block->>'note') AS note_id,
COUNT(distinct block_list.page_id) AS count
FROM block_list
WHERE block_list.block->>'type' = 'note'
GROUP BY block->>'note'
)
UPDATE note
SET "pageCount" = clipped_notes.count
FROM clipped_notes
WHERE note.id = clipped_notes.note_id;
`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "pageCount"`);
}
}
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class EntrancePageStyle1755574887486 {
name = 'EntrancePageStyle1755574887486'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "clientOptions" jsonb NOT NULL DEFAULT '{}'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "clientOptions"`);
}
}
@@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class NonCascadingPageEyeCatching1756062689648 {
name = 'NonCascadingPageEyeCatching1756062689648'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "page" DROP CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa"`);
await queryRunner.query(`ALTER TABLE "page" ADD CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa" FOREIGN KEY ("eyeCatchingImageId") REFERENCES "drive_file"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "page" DROP CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa"`);
await queryRunner.query(`ALTER TABLE "page" ADD CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa" FOREIGN KEY ("eyeCatchingImageId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
}
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class SensitiveAd1757823175259 {
name = 'SensitiveAd1757823175259'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "ad" ADD "isSensitive" boolean NOT NULL DEFAULT false`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "isSensitive"`);
}
}
+48 -47
View File
@@ -11,6 +11,7 @@
"start:test": "cross-env NODE_ENV=test node ./built/boot/entry.js",
"migrate": "pnpm typeorm migration:run -d ormconfig.js",
"revert": "pnpm typeorm migration:revert -d ormconfig.js",
"cli": "node ./built/boot/cli.js",
"check:connect": "node ./scripts/check_connect.js",
"build": "swc src -d built -D --strip-leading-paths",
"build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc --strip-leading-paths",
@@ -38,17 +39,17 @@
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
"@swc/core-darwin-arm64": "1.12.0",
"@swc/core-darwin-x64": "1.12.0",
"@swc/core-darwin-arm64": "1.13.5",
"@swc/core-darwin-x64": "1.13.5",
"@swc/core-freebsd-x64": "1.3.11",
"@swc/core-linux-arm-gnueabihf": "1.12.0",
"@swc/core-linux-arm64-gnu": "1.12.0",
"@swc/core-linux-arm64-musl": "1.12.0",
"@swc/core-linux-x64-gnu": "1.12.0",
"@swc/core-linux-x64-musl": "1.12.0",
"@swc/core-win32-arm64-msvc": "1.12.0",
"@swc/core-win32-ia32-msvc": "1.12.0",
"@swc/core-win32-x64-msvc": "1.12.0",
"@swc/core-linux-arm-gnueabihf": "1.13.5",
"@swc/core-linux-arm64-gnu": "1.13.5",
"@swc/core-linux-arm64-musl": "1.13.5",
"@swc/core-linux-x64-gnu": "1.13.5",
"@swc/core-linux-x64-musl": "1.13.5",
"@swc/core-win32-arm64-msvc": "1.13.5",
"@swc/core-win32-ia32-msvc": "1.13.5",
"@swc/core-win32-x64-msvc": "1.13.5",
"@tensorflow/tfjs": "4.22.0",
"@tensorflow/tfjs-node": "4.22.0",
"bufferutil": "4.0.9",
@@ -68,31 +69,31 @@
"utf-8-validate": "6.0.5"
},
"dependencies": {
"@aws-sdk/client-s3": "3.826.0",
"@aws-sdk/lib-storage": "3.826.0",
"@aws-sdk/client-s3": "3.883.0",
"@aws-sdk/lib-storage": "3.883.0",
"@discordapp/twemoji": "16.0.1",
"@fastify/accepts": "5.0.2",
"@fastify/cookie": "11.0.2",
"@fastify/cors": "10.1.0",
"@fastify/express": "4.0.2",
"@fastify/http-proxy": "10.0.2",
"@fastify/multipart": "9.0.3",
"@fastify/multipart": "9.2.1",
"@fastify/static": "8.2.0",
"@fastify/view": "10.0.2",
"@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.2.1",
"@napi-rs/canvas": "0.1.71",
"@nestjs/common": "11.1.3",
"@nestjs/core": "11.1.3",
"@nestjs/testing": "11.1.3",
"@misskey-dev/summaly": "5.2.3",
"@napi-rs/canvas": "0.1.79",
"@nestjs/common": "11.1.6",
"@nestjs/core": "11.1.6",
"@nestjs/testing": "11.1.6",
"@peertube/http-signature": "1.7.0",
"@sentry/node": "8.55.0",
"@sentry/profiling-node": "8.55.0",
"@simplewebauthn/server": "12.0.0",
"@sinonjs/fake-timers": "11.3.1",
"@smithy/node-http-handler": "2.5.0",
"@swc/cli": "0.7.7",
"@swc/core": "1.12.0",
"@swc/cli": "0.7.8",
"@swc/core": "1.13.5",
"@twemoji/parser": "16.0.0",
"@types/redis-info": "3.0.3",
"accepts": "1.3.8",
@@ -102,10 +103,10 @@
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"body-parser": "1.20.3",
"bullmq": "5.53.2",
"bullmq": "5.58.5",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.2",
"chalk": "5.4.1",
"chalk": "5.6.0",
"chalk-template": "1.1.0",
"chokidar": "4.0.3",
"cli-highlight": "2.1.11",
@@ -113,18 +114,18 @@
"content-disposition": "0.5.4",
"date-fns": "2.30.0",
"deep-email-validator": "0.1.21",
"fastify": "5.3.3",
"fastify": "5.6.0",
"fastify-raw-body": "5.0.0",
"feed": "4.2.2",
"file-type": "19.6.0",
"fluent-ffmpeg": "2.1.3",
"form-data": "4.0.3",
"got": "14.4.7",
"form-data": "4.0.4",
"got": "14.4.8",
"happy-dom": "16.8.1",
"hpagent": "1.2.0",
"htmlescape": "1.1.1",
"http-link-header": "1.1.3",
"ioredis": "5.6.1",
"ioredis": "5.7.0",
"ip-cidr": "4.0.2",
"ipaddr.js": "2.2.0",
"is-svg": "5.1.0",
@@ -134,13 +135,13 @@
"jsonld": "8.3.3",
"jsrsasign": "11.1.0",
"juice": "11.0.1",
"meilisearch": "0.51.0",
"meilisearch": "0.52.0",
"mfm-js": "0.25.0",
"microformats-parser": "2.0.3",
"microformats-parser": "2.0.4",
"mime-types": "2.1.35",
"misskey-js": "workspace:*",
"misskey-reversi": "workspace:*",
"ms": "3.0.0-canary.1",
"ms": "3.0.0-canary.202508261828",
"nanoid": "5.1.5",
"nested-property": "4.0.0",
"node-fetch": "3.3.2",
@@ -150,9 +151,9 @@
"oauth2orize": "1.12.0",
"oauth2orize-pkce": "0.1.2",
"os-utils": "0.0.14",
"otpauth": "9.4.0",
"otpauth": "9.4.1",
"parse5": "7.3.0",
"pg": "8.16.0",
"pg": "8.16.3",
"pkce-challenge": "4.1.0",
"probe-image-size": "7.2.3",
"promise-limit": "2.7.0",
@@ -174,25 +175,25 @@
"slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"systeminformation": "5.27.1",
"systeminformation": "5.27.8",
"tinycolor2": "1.6.0",
"tmp": "0.2.3",
"tmp": "0.2.5",
"tsc-alias": "1.8.16",
"tsconfig-paths": "4.2.0",
"typeorm": "0.3.24",
"typescript": "5.8.3",
"typeorm": "0.3.26",
"typescript": "5.9.2",
"ulid": "2.4.0",
"vary": "1.1.2",
"web-push": "3.6.7",
"ws": "8.18.2",
"ws": "8.18.3",
"xev": "3.0.2"
},
"devDependencies": {
"@jest/globals": "29.7.0",
"@nestjs/platform-express": "10.4.19",
"@sentry/vue": "9.28.0",
"@nestjs/platform-express": "10.4.20",
"@sentry/vue": "9.46.0",
"@simplewebauthn/types": "12.0.0",
"@swc/jest": "0.2.38",
"@swc/jest": "0.2.39",
"@types/accepts": "1.3.7",
"@types/archiver": "6.0.3",
"@types/bcryptjs": "2.4.6",
@@ -209,19 +210,19 @@
"@types/jsrsasign": "10.5.15",
"@types/mime-types": "2.1.4",
"@types/ms": "0.7.34",
"@types/node": "22.15.31",
"@types/nodemailer": "6.4.17",
"@types/node": "22.18.1",
"@types/nodemailer": "6.4.19",
"@types/oauth": "0.9.6",
"@types/oauth2orize": "1.11.5",
"@types/oauth2orize-pkce": "0.1.2",
"@types/pg": "8.15.4",
"@types/pg": "8.15.5",
"@types/pug": "2.0.10",
"@types/qrcode": "1.5.5",
"@types/random-seed": "0.3.5",
"@types/ratelimiter": "3.4.6",
"@types/rename": "1.0.7",
"@types/sanitize-html": "2.16.0",
"@types/semver": "7.7.0",
"@types/semver": "7.7.1",
"@types/simple-oauth2": "5.0.7",
"@types/sinonjs__fake-timers": "8.1.5",
"@types/supertest": "6.0.3",
@@ -230,11 +231,11 @@
"@types/vary": "1.1.3",
"@types/web-push": "3.6.4",
"@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.34.0",
"@typescript-eslint/parser": "8.34.0",
"@typescript-eslint/eslint-plugin": "8.42.0",
"@typescript-eslint/parser": "8.42.0",
"aws-sdk-client-mock": "4.1.0",
"cross-env": "7.0.3",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-import": "2.32.0",
"execa": "8.0.1",
"fkill": "9.0.0",
"jest": "29.7.0",
@@ -242,6 +243,6 @@
"nodemon": "3.1.10",
"pid-port": "1.0.2",
"simple-oauth2": "5.1.0",
"supertest": "7.1.1"
"supertest": "7.1.4"
}
}
+49
View File
@@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import 'reflect-metadata';
import { EventEmitter } from 'node:events';
import { NestFactory } from '@nestjs/core';
import { CommandModule } from '@/cli/CommandModule.js';
import { NestLogger } from '@/NestLogger.js';
import { CommandService } from '@/cli/CommandService.js';
process.title = 'Misskey Cli';
Error.stackTraceLimit = Infinity;
EventEmitter.defaultMaxListeners = 128;
const app = await NestFactory.createApplicationContext(CommandModule, {
logger: new NestLogger(),
});
const commandService = app.get(CommandService);
const command = process.argv[2] ?? 'help';
switch (command) {
case 'help': {
console.log('Available commands:');
console.log(' help - Displays this help message');
console.log(' reset-captcha - Resets the captcha');
break;
}
case 'ping': {
await commandService.ping();
break;
}
case 'reset-captcha': {
await commandService.resetCaptcha();
console.log('Captcha has been reset.');
break;
}
default: {
console.error(`Unrecognized command: ${command}`);
console.error('Use "help" to see available commands.');
process.exit(1);
}
}
process.exit(0);
+23
View File
@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Module } from '@nestjs/common';
import { CoreModule } from '@/core/CoreModule.js';
import { GlobalModule } from '@/GlobalModule.js';
import { CommandService } from './CommandService.js';
@Module({
imports: [
GlobalModule,
CoreModule,
],
providers: [
CommandService,
],
exports: [
CommandService,
],
})
export class CommandModule {}
@@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import { MetaService } from '@/core/MetaService.js';
@Injectable()
export class CommandService {
private logger: Logger;
constructor(
@Inject(DI.config)
private config: Config,
private metaService: MetaService,
) {
}
@bindThis
public async ping() {
console.log('pong');
}
@bindThis
public async resetCaptcha() {
await this.metaService.update({
enableHcaptcha: false,
hcaptchaSiteKey: null,
hcaptchaSecretKey: null,
enableMcaptcha: false,
mcaptchaSitekey: null,
mcaptchaSecretKey: null,
mcaptchaInstanceUrl: null,
enableRecaptcha: false,
recaptchaSiteKey: null,
recaptchaSecretKey: null,
enableTurnstile: false,
turnstileSiteKey: null,
turnstileSecretKey: null,
enableTestcaptcha: false,
});
}
}
+2 -2
View File
@@ -29,7 +29,7 @@ export class AiService {
}
@bindThis
public async detectSensitive(path: string): Promise<nsfw.PredictionType[] | null> {
public async detectSensitive(source: string | Buffer): Promise<nsfw.PredictionType[] | null> {
try {
if (isSupportedCpu === undefined) {
isSupportedCpu = await this.computeIsSupportedCpu();
@@ -51,7 +51,7 @@ export class AiService {
});
}
const buffer = await fs.promises.readFile(path);
const buffer = source instanceof Buffer ? source : await fs.promises.readFile(source);
const image = await tf.node.decodeImage(buffer, 3) as any;
try {
const predictions = await this.model.classify(image);
+6
View File
@@ -78,6 +78,7 @@ import { ChannelFollowingService } from './ChannelFollowingService.js';
import { ChatService } from './ChatService.js';
import { RegistryApiService } from './RegistryApiService.js';
import { ReversiService } from './ReversiService.js';
import { PageService } from './PageService.js';
import { ChartLoggerService } from './chart/ChartLoggerService.js';
import FederationChart from './chart/charts/federation.js';
@@ -227,6 +228,7 @@ const $ChannelFollowingService: Provider = { provide: 'ChannelFollowingService',
const $ChatService: Provider = { provide: 'ChatService', useExisting: ChatService };
const $RegistryApiService: Provider = { provide: 'RegistryApiService', useExisting: RegistryApiService };
const $ReversiService: Provider = { provide: 'ReversiService', useExisting: ReversiService };
const $PageService: Provider = { provide: 'PageService', useExisting: PageService };
const $ChartLoggerService: Provider = { provide: 'ChartLoggerService', useExisting: ChartLoggerService };
const $FederationChart: Provider = { provide: 'FederationChart', useExisting: FederationChart };
@@ -379,6 +381,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
ChatService,
RegistryApiService,
ReversiService,
PageService,
ChartLoggerService,
FederationChart,
@@ -527,6 +530,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$ChatService,
$RegistryApiService,
$ReversiService,
$PageService,
$ChartLoggerService,
$FederationChart,
@@ -676,6 +680,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
ChatService,
RegistryApiService,
ReversiService,
PageService,
FederationChart,
NotesChart,
@@ -822,6 +827,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$ChatService,
$RegistryApiService,
$ReversiService,
$PageService,
$FederationChart,
$NotesChart,
+19 -10
View File
@@ -21,6 +21,7 @@ import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import type { PredictionType } from 'nsfwjs';
import { isMimeImage } from '@/misc/is-mime-image.js';
export type FileInfo = {
size: number;
@@ -204,16 +205,7 @@ export class FileInfoService {
return [sensitive, porn];
}
if ([
'image/jpeg',
'image/png',
'image/webp',
].includes(mime)) {
const result = await this.aiService.detectSensitive(source);
if (result) {
[sensitive, porn] = judgePrediction(result);
}
} else if (analyzeVideo && (mime === 'image/apng' || mime.startsWith('video/'))) {
if (analyzeVideo && (mime === 'image/apng' || mime.startsWith('video/'))) {
const [outDir, disposeOutDir] = await createTempDir();
try {
const command = FFmpeg()
@@ -281,6 +273,23 @@ export class FileInfoService {
} finally {
disposeOutDir();
}
} else if (isMimeImage(mime, 'sharp-convertible-image-with-bmp')) {
/*
* tfjs-node sharp PNG
* 使299x299に事前にリサイズする
*/
const png = await (await sharpBmp(source, mime))
.resize(299, 299, {
withoutEnlargement: false,
})
.rotate()
.flatten({ background: { r: 119, g: 119, b: 119 } }) // 透過部分を18%グレーで塗りつぶす
.png()
.toBuffer();
const result = await this.aiService.detectSensitive(png);
if (result) {
[sensitive, porn] = judgePrediction(result);
}
}
return [sensitive, porn];
@@ -6,6 +6,7 @@
import * as http from 'node:http';
import * as https from 'node:https';
import * as net from 'node:net';
import * as stream from 'node:stream';
import ipaddr from 'ipaddr.js';
import CacheableLookup from 'cacheable-lookup';
import fetch from 'node-fetch';
@@ -26,12 +27,6 @@ export type HttpRequestSendOptions = {
validators?: ((res: Response) => void)[];
};
declare module 'node:http' {
interface Agent {
createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket;
}
}
class HttpRequestServiceAgent extends http.Agent {
constructor(
private config: Config,
@@ -41,11 +36,11 @@ class HttpRequestServiceAgent extends http.Agent {
}
@bindThis
public createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
public createConnection(options: http.ClientRequestArgs, callback?: (err: Error | null, stream: stream.Duplex) => void): stream.Duplex {
const socket = super.createConnection(options, callback)
.on('connect', () => {
const address = socket.remoteAddress;
if (process.env.NODE_ENV === 'production') {
if (socket instanceof net.Socket && process.env.NODE_ENV === 'production') {
const address = socket.remoteAddress;
if (address && ipaddr.isValid(address)) {
if (this.isPrivateIp(address)) {
socket.destroy(new Error(`Blocked address: ${address}`));
@@ -80,11 +75,11 @@ class HttpsRequestServiceAgent extends https.Agent {
}
@bindThis
public createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
public createConnection(options: http.ClientRequestArgs, callback?: (err: Error | null, stream: stream.Duplex) => void): stream.Duplex {
const socket = super.createConnection(options, callback)
.on('connect', () => {
const address = socket.remoteAddress;
if (process.env.NODE_ENV === 'production') {
if (socket instanceof net.Socket && process.env.NODE_ENV === 'production') {
const address = socket.remoteAddress;
if (address && ipaddr.isValid(address)) {
if (this.isPrivateIp(address)) {
socket.destroy(new Error(`Blocked address: ${address}`));
+223
View File
@@ -0,0 +1,223 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { DataSource, In, Not } from 'typeorm';
import { DI } from '@/di-symbols.js';
import {
type NotesRepository,
MiPage,
type PagesRepository,
MiDriveFile,
type UsersRepository,
MiNote,
} from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { IdService } from '@/core/IdService.js';
import type { MiUser } from '@/models/User.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
export interface PageBody {
title: string;
name: string;
summary: string | null;
content: Array<Record<string, any>>;
variables: Array<Record<string, any>>;
script: string;
eyeCatchingImage?: MiDriveFile | null;
font: string;
alignCenter: boolean;
hideTitleWhenPinned: boolean;
}
@Injectable()
export class PageService {
constructor(
@Inject(DI.db)
private db: DataSource,
@Inject(DI.pagesRepository)
private pagesRepository: PagesRepository,
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private roleService: RoleService,
private moderationLogService: ModerationLogService,
private idService: IdService,
) {
}
@bindThis
public async create(
me: MiUser,
body: PageBody,
): Promise<MiPage> {
await this.pagesRepository.findBy({
userId: me.id,
name: body.name,
}).then(result => {
if (result.length > 0) {
throw new IdentifiableError('1a79e38e-3d83-4423-845b-a9d83ff93b61');
}
});
const page = await this.pagesRepository.insertOne(new MiPage({
id: this.idService.gen(),
updatedAt: new Date(),
title: body.title,
name: body.name,
summary: body.summary,
content: body.content,
variables: body.variables,
script: body.script,
eyeCatchingImageId: body.eyeCatchingImage ? body.eyeCatchingImage.id : null,
userId: me.id,
visibility: 'public',
alignCenter: body.alignCenter,
hideTitleWhenPinned: body.hideTitleWhenPinned,
font: body.font,
}));
const referencedNotes = this.collectReferencedNotes(page.content);
if (referencedNotes.length > 0) {
await this.notesRepository.increment({ id: In(referencedNotes) }, 'pageCount', 1);
}
return page;
}
@bindThis
public async update(
me: MiUser,
pageId: MiPage['id'],
body: Partial<PageBody>,
): Promise<void> {
await this.db.transaction(async (transaction) => {
const page = await transaction.findOne(MiPage, {
where: {
id: pageId,
},
lock: { mode: 'for_no_key_update' },
});
if (page == null) {
throw new IdentifiableError('66aefd3c-fdb2-4a71-85ae-cc18bea85d3f');
}
if (page.userId !== me.id) {
throw new IdentifiableError('d0017699-8256-46f1-aed4-bc03bed73616');
}
if (body.name != null) {
await transaction.findBy(MiPage, {
id: Not(pageId),
userId: me.id,
name: body.name,
}).then(result => {
if (result.length > 0) {
throw new IdentifiableError('d05bfe24-24b6-4ea2-a3ec-87cc9bf4daa4');
}
});
}
await transaction.update(MiPage, page.id, {
updatedAt: new Date(),
title: body.title,
name: body.name,
summary: body.summary === undefined ? page.summary : body.summary,
content: body.content,
variables: body.variables,
script: body.script,
alignCenter: body.alignCenter,
hideTitleWhenPinned: body.hideTitleWhenPinned,
font: body.font,
eyeCatchingImageId: body.eyeCatchingImage === undefined ? undefined : (body.eyeCatchingImage?.id ?? null),
});
console.log("page.content", page.content);
if (body.content != null) {
const beforeReferencedNotes = this.collectReferencedNotes(page.content);
const afterReferencedNotes = this.collectReferencedNotes(body.content);
const removedNotes = beforeReferencedNotes.filter(noteId => !afterReferencedNotes.includes(noteId));
const addedNotes = afterReferencedNotes.filter(noteId => !beforeReferencedNotes.includes(noteId));
if (removedNotes.length > 0) {
await transaction.decrement(MiNote, { id: In(removedNotes) }, 'pageCount', 1);
}
if (addedNotes.length > 0) {
await transaction.increment(MiNote, { id: In(addedNotes) }, 'pageCount', 1);
}
}
});
}
@bindThis
public async delete(me: MiUser, pageId: MiPage['id']): Promise<void> {
await this.db.transaction(async (transaction) => {
const page = await transaction.findOne(MiPage, {
where: {
id: pageId,
},
lock: { mode: 'pessimistic_write' }, // same lock level as DELETE
});
if (page == null) {
throw new IdentifiableError('66aefd3c-fdb2-4a71-85ae-cc18bea85d3f');
}
if (!await this.roleService.isModerator(me) && page.userId !== me.id) {
throw new IdentifiableError('d0017699-8256-46f1-aed4-bc03bed73616');
}
await transaction.delete(MiPage, page.id);
if (page.userId !== me.id) {
const user = await this.usersRepository.findOneByOrFail({ id: page.userId });
this.moderationLogService.log(me, 'deletePage', {
pageId: page.id,
pageUserId: page.userId,
pageUserUsername: user.username,
page,
});
}
const referencedNotes = this.collectReferencedNotes(page.content);
if (referencedNotes.length > 0) {
await transaction.decrement(MiNote, { id: In(referencedNotes) }, 'pageCount', 1);
}
});
}
collectReferencedNotes(content: MiPage['content']): string[] {
const referencingNotes = new Set<string>();
const recursiveCollect = (content: unknown[]) => {
for (const contentElement of content) {
if (typeof contentElement === 'object'
&& contentElement !== null
&& 'type' in contentElement) {
if (contentElement.type === 'note'
&& 'note' in contentElement
&& typeof contentElement.note === 'string') {
referencingNotes.add(contentElement.note);
}
if (contentElement.type === 'section'
&& 'children' in contentElement
&& Array.isArray(contentElement.children)) {
recursiveCollect(contentElement.children);
}
}
}
};
recursiveCollect(content);
return [...referencingNotes];
}
}
+7 -6
View File
@@ -103,6 +103,7 @@ export class QueueService {
for (const def of REPEATABLE_SYSTEM_JOB_DEF) {
this.systemQueue.upsertJobScheduler(def.name, {
pattern: def.pattern,
immediately: false,
}, {
name: def.name,
opts: {
@@ -755,8 +756,8 @@ export class QueueService {
@bindThis
public async queueRetryJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
const job = await queue.getJob(jobId);
if (job != null) {
if (job.finishedOn != null) {
await job.retry();
} else {
@@ -768,8 +769,8 @@ export class QueueService {
@bindThis
public async queueRemoveJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
const job = await queue.getJob(jobId);
if (job != null) {
await job.remove();
}
}
@@ -802,8 +803,8 @@ export class QueueService {
@bindThis
public async queueGetJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
const job = await queue.getJob(jobId);
if (job != null) {
return this.packJobData(job);
} else {
throw new Error(`Job not found: ${jobId}`);
+10 -5
View File
@@ -31,6 +31,7 @@ import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { NotificationService } from '@/core/NotificationService.js';
import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common';
// misskey-js の rolePolicies と同期すべし
export type RolePolicies = {
gtlAvailable: boolean;
ltlAvailable: boolean;
@@ -43,6 +44,7 @@ export type RolePolicies = {
canManageCustomEmojis: boolean;
canManageAvatarDecorations: boolean;
canSearchNotes: boolean;
canSearchUsers: boolean;
canUseTranslator: boolean;
canHideAds: boolean;
driveCapacityMb: number;
@@ -82,6 +84,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
canManageCustomEmojis: false,
canManageAvatarDecorations: false,
canSearchNotes: false,
canSearchUsers: true,
canUseTranslator: true,
canHideAds: false,
driveCapacityMb: 100,
@@ -98,14 +101,15 @@ export const DEFAULT_POLICIES: RolePolicies = {
userEachUserListsLimit: 50,
rateLimitFactor: 1,
avatarDecorationLimit: 1,
canImportAntennas: true,
canImportBlocking: true,
canImportFollowing: true,
canImportMuting: true,
canImportUserLists: true,
canImportAntennas: false,
canImportBlocking: false,
canImportFollowing: false,
canImportMuting: false,
canImportUserLists: false,
chatAvailability: 'available',
uploadableFileTypes: [
'text/plain',
'text/csv',
'application/json',
'image/*',
'video/*',
@@ -402,6 +406,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
canManageAvatarDecorations: calc('canManageAvatarDecorations', vs => vs.some(v => v === true)),
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
canSearchUsers: calc('canSearchUsers', vs => vs.some(v => v === true)),
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
@@ -85,6 +85,7 @@ function generateDummyNote(override?: Partial<MiNote>): MiNote {
renoteCount: 10,
repliesCount: 5,
clippedCount: 0,
pageCount: 0,
reactions: {},
visibility: 'public',
uri: null,
@@ -243,7 +244,6 @@ export class WebhookTestService {
case 'reaction':
return;
default: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _exhaustiveAssertion: never = params.type;
return;
}
@@ -326,7 +326,6 @@ export class WebhookTestService {
break;
}
default: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _exhaustiveAssertion: never = params.type;
return;
}
@@ -411,7 +410,7 @@ export class WebhookTestService {
name: user.name,
username: user.username,
host: user.host,
avatarUrl: user.avatarId == null ? null : user.avatarUrl,
avatarUrl: (user.avatarId == null ? null : user.avatarUrl) ?? '',
avatarBlurhash: user.avatarId == null ? null : user.avatarBlurhash,
avatarDecorations: user.avatarDecorations.map(it => ({
id: it.id,
@@ -54,12 +54,13 @@ export class ChatEntityService {
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
const reactions: { user: Packed<'UserLite'>; reaction: string; }[] = [];
// userは削除されている可能性があるのでnull許容
const reactions: { user: Packed<'UserLite'> | null; reaction: string; }[] = [];
for (const record of message.reactions) {
const [userId, reaction] = record.split('/');
reactions.push({
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId),
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId).catch(() => null),
reaction,
});
}
@@ -76,7 +77,7 @@ export class ChatEntityService {
toRoom: message.toRoomId ? (packedRooms?.get(message.toRoomId) ?? await this.packRoom(message.toRoom ?? message.toRoomId, me)) : undefined,
fileId: message.fileId,
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
reactions,
reactions: reactions.filter((r): r is { user: Packed<'UserLite'>; reaction: string; } => r.user != null),
};
}
@@ -108,6 +109,7 @@ export class ChatEntityService {
}
}
// TODO: packedUsersに削除されたユーザーもnullとして含める
const [packedUsers, packedFiles, packedRooms] = await Promise.all([
this.userEntityService.packMany(users, me)
.then(users => new Map(users.map(u => [u.id, u]))),
@@ -183,12 +185,13 @@ export class ChatEntityService {
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
const reactions: { user: Packed<'UserLite'>; reaction: string; }[] = [];
// userは削除されている可能性があるのでnull許容
const reactions: { user: Packed<'UserLite'> | null; reaction: string; }[] = [];
for (const record of message.reactions) {
const [userId, reaction] = record.split('/');
reactions.push({
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId),
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId).catch(() => null),
reaction,
});
}
@@ -202,7 +205,7 @@ export class ChatEntityService {
toRoomId: message.toRoomId!,
fileId: message.fileId,
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
reactions,
reactions: reactions.filter((r): r is { user: Packed<'UserLite'>; reaction: string; } => r.user != null),
};
}
@@ -109,6 +109,7 @@ export class MetaEntityService {
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH,
defaultLightTheme,
defaultDarkTheme,
clientOptions: instance.clientOptions,
ads: ads.map(ad => ({
id: ad.id,
url: ad.url,
@@ -116,6 +117,7 @@ export class MetaEntityService {
ratio: ad.ratio,
imageUrl: ad.imageUrl,
dayOfWeek: ad.dayOfWeek,
isSensitive: ad.isSensitive ? true : undefined,
})),
notesPerOneAd: instance.notesPerOneAd,
enableEmail: instance.enableEmail,
@@ -49,15 +49,12 @@ export class NoteReactionEntityService implements OnModuleInit {
public async pack(
src: MiNoteReaction['id'] | MiNoteReaction,
me?: { id: MiUser['id'] } | null | undefined,
options?: {
withNote: boolean;
},
options?: object,
hints?: {
packedUser?: Packed<'UserLite'>
},
): Promise<Packed<'NoteReaction'>> {
const opts = Object.assign({
withNote: false,
}, options);
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
@@ -67,9 +64,6 @@ export class NoteReactionEntityService implements OnModuleInit {
createdAt: this.idService.parse(reaction.id).date.toISOString(),
user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me),
type: this.reactionService.convertLegacyReaction(reaction.reaction),
...(opts.withNote ? {
note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me),
} : {}),
};
}
@@ -77,16 +71,50 @@ export class NoteReactionEntityService implements OnModuleInit {
public async packMany(
reactions: MiNoteReaction[],
me?: { id: MiUser['id'] } | null | undefined,
options?: {
withNote: boolean;
},
options?: object,
): Promise<Packed<'NoteReaction'>[]> {
const opts = Object.assign({
withNote: false,
}, options);
const _users = reactions.map(({ user, userId }) => user ?? userId);
const _userMap = await this.userEntityService.packMany(_users, me)
.then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(reactions.map(reaction => this.pack(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) })));
}
@bindThis
public async packWithNote(
src: MiNoteReaction['id'] | MiNoteReaction,
me?: { id: MiUser['id'] } | null | undefined,
options?: object,
hints?: {
packedUser?: Packed<'UserLite'>
},
): Promise<Packed<'NoteReactionWithNote'>> {
const opts = Object.assign({
}, options);
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
return {
id: reaction.id,
createdAt: this.idService.parse(reaction.id).date.toISOString(),
user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me),
type: this.reactionService.convertLegacyReaction(reaction.reaction),
note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me),
};
}
@bindThis
public async packManyWithNote(
reactions: MiNoteReaction[],
me?: { id: MiUser['id'] } | null | undefined,
options?: object,
): Promise<Packed<'NoteReactionWithNote'>[]> {
const opts = Object.assign({
}, options);
const _users = reactions.map(({ user, userId }) => user ?? userId);
const _userMap = await this.userEntityService.packMany(_users, me)
.then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(reactions.map(reaction => this.packWithNote(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) })));
}
}
@@ -471,8 +471,8 @@ export class UserEntityService implements OnModuleInit {
(profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount :
null;
const isModerator = isMe && isDetailed ? this.roleService.isModerator(user) : null;
const isAdmin = isMe && isDetailed ? this.roleService.isAdministrator(user) : null;
const isModerator = isMe && isDetailed ? this.roleService.isModerator(user) : undefined;
const isAdmin = isMe && isDetailed ? this.roleService.isAdministrator(user) : undefined;
const unreadAnnouncements = isMe && isDetailed ?
(await this.announcementService.getUnreadAnnouncements(user)).map((announcement) => ({
createdAt: this.idService.parse(announcement.id).date.toISOString(),
@@ -481,6 +481,7 @@ export class UserEntityService implements OnModuleInit {
const notificationsInfo = isMe && isDetailed ? await this.getNotificationsInfo(user.id) : null;
// TODO: 例えば avatarUrl: true など間違った型を設定しても型エラーにならないのをどうにかする(ジェネリクス使わない方法で実装するしかなさそう?)
const packed = {
id: user.id,
name: user.name,
+4 -1
View File
@@ -22,7 +22,7 @@ import { packedFollowingSchema } from '@/models/json-schema/following.js';
import { packedMutingSchema } from '@/models/json-schema/muting.js';
import { packedRenoteMutingSchema } from '@/models/json-schema/renote-muting.js';
import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js';
import { packedNoteReactionSchema, packedNoteReactionWithNoteSchema } from '@/models/json-schema/note-reaction.js';
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js';
import { packedPageBlockSchema, packedPageSchema } from '@/models/json-schema/page.js';
@@ -65,6 +65,7 @@ import {
packedMetaDetailedSchema,
packedMetaLiteSchema,
} from '@/models/json-schema/meta.js';
import { packedUserWebhookSchema } from '@/models/json-schema/user-webhook.js';
import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessageLiteForRoomSchema, packedChatMessageLiteFor1on1Schema } from '@/models/json-schema/chat-message.js';
@@ -92,6 +93,7 @@ export const refs = {
Note: packedNoteSchema,
NoteDraft: packedNoteDraftSchema,
NoteReaction: packedNoteReactionSchema,
NoteReactionWithNote: packedNoteReactionWithNoteSchema,
NoteFavorite: packedNoteFavoriteSchema,
Notification: packedNotificationSchema,
DriveFile: packedDriveFileSchema,
@@ -133,6 +135,7 @@ export const refs = {
MetaLite: packedMetaLiteSchema,
MetaDetailedOnly: packedMetaDetailedOnlySchema,
MetaDetailed: packedMetaDetailedSchema,
UserWebhook: packedUserWebhookSchema,
SystemWebhook: packedSystemWebhookSchema,
AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
ChatMessage: packedChatMessageSchema,
+7
View File
@@ -54,10 +54,17 @@ export class MiAd {
length: 8192, nullable: false,
})
public memo: string;
@Column('integer', {
default: 0, nullable: false,
})
public dayOfWeek: number;
@Column('boolean', {
default: false,
})
public isSensitive: boolean;
constructor(data: Partial<MiAd>) {
if (data == null) return;
+5
View File
@@ -716,6 +716,11 @@ export class MiMeta {
default: 90, // days
})
public remoteNotesCleaningExpiryDaysForEachNotes: number;
@Column('jsonb', {
default: { },
})
public clientOptions: Record<string, any>;
}
export type SoftwareSuspension = {
+7
View File
@@ -114,6 +114,13 @@ export class MiNote {
})
public clippedCount: number;
// The number of note page blocks referencing this note.
// This column is used by Remote Note Cleaning and manually updated rather than automatically with triggers.
@Column('smallint', {
default: 0,
})
public pageCount: number;
@Column('jsonb', {
default: {},
})
@@ -10,6 +10,7 @@ import { MiAccessToken } from './AccessToken.js';
import { MiRole } from './Role.js';
import { MiDriveFile } from './DriveFile.js';
// misskey-js の notificationTypes と同期すべし
export type MiNotification = {
type: 'note';
id: string;
+1 -1
View File
@@ -69,7 +69,7 @@ export class MiPage {
public eyeCatchingImageId: MiDriveFile['id'] | null;
@ManyToOne(type => MiDriveFile, {
onDelete: 'CASCADE',
onDelete: 'SET NULL',
})
@JoinColumn()
public eyeCatchingImage: MiDriveFile | null;
@@ -60,5 +60,10 @@ export const packedAdSchema = {
optional: false,
nullable: false,
},
isSensitive: {
type: 'boolean',
optional: false,
nullable: false,
},
},
} as const;
@@ -71,6 +71,10 @@ export const packedMetaLiteSchema = {
type: 'string',
optional: false, nullable: true,
},
clientOptions: {
type: 'object',
optional: false, nullable: false,
},
disableRegistration: {
type: 'boolean',
optional: false, nullable: false,
@@ -191,6 +195,10 @@ export const packedMetaLiteSchema = {
type: 'integer',
optional: false, nullable: false,
},
isSensitive: {
type: 'boolean',
optional: true, nullable: false,
},
},
},
},
@@ -10,7 +10,6 @@ export const packedNoteReactionSchema = {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
@@ -28,3 +27,33 @@ export const packedNoteReactionSchema = {
},
},
} as const;
export const packedNoteReactionWithNoteSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
user: {
type: 'object',
optional: false, nullable: false,
ref: 'UserLite',
},
type: {
type: 'string',
optional: false, nullable: false,
},
note: {
type: 'object',
optional: false, nullable: false,
ref: 'Note',
},
},
} as const;
@@ -212,6 +212,10 @@ export const packedRolePoliciesSchema = {
type: 'boolean',
optional: false, nullable: false,
},
canSearchUsers: {
type: 'boolean',
optional: false, nullable: false,
},
canUseTranslator: {
type: 'boolean',
optional: false, nullable: false,
@@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { webhookEventTypes } from '@/models/Webhook.js';
export const packedUserWebhookSchema = {
type: 'object',
properties: {
id: {
type: 'string',
format: 'id',
optional: false, nullable: false,
},
userId: {
type: 'string',
format: 'id',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
},
on: {
type: 'array',
items: {
type: 'string',
optional: false, nullable: false,
enum: webhookEventTypes,
},
},
url: {
type: 'string',
optional: false, nullable: false,
},
secret: {
type: 'string',
optional: false, nullable: false,
},
active: {
type: 'boolean',
optional: false, nullable: false,
},
latestSentAt: {
type: 'string',
format: 'date-time',
optional: false, nullable: true,
},
latestStatus: {
type: 'integer',
optional: false, nullable: true,
},
},
} as const;
@@ -65,7 +65,7 @@ export const packedUserLiteSchema = {
avatarUrl: {
type: 'string',
format: 'url',
nullable: true, optional: false,
nullable: false, optional: false,
},
avatarBlurhash: {
type: 'string',
@@ -465,11 +465,11 @@ export const packedMeDetailedOnlySchema = {
},
isModerator: {
type: 'boolean',
nullable: true, optional: false,
nullable: false, optional: false,
},
isAdmin: {
type: 'boolean',
nullable: true, optional: false,
nullable: false, optional: false,
},
injectFeaturedNote: {
type: 'boolean',
@@ -591,7 +591,7 @@ export const packedMeDetailedOnlySchema = {
},
mutedInstances: {
type: 'array',
nullable: true, optional: false,
nullable: false, optional: false,
items: {
type: 'string',
nullable: false, optional: false,
@@ -5,9 +5,9 @@
import { setTimeout } from 'node:timers/promises';
import { Inject, Injectable } from '@nestjs/common';
import { And, Brackets, In, IsNull, LessThan, MoreThan, Not } from 'typeorm';
import { DataSource, IsNull, LessThan, QueryFailedError, Not } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { MiMeta, MiNote, NoteFavoritesRepository, NotesRepository, UserNotePiningsRepository } from '@/models/_.js';
import type { MiMeta, MiNote, NotesRepository } from '@/models/_.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
@@ -25,11 +25,8 @@ export class CleanRemoteNotesProcessorService {
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
@Inject(DI.noteFavoritesRepository)
private noteFavoritesRepository: NoteFavoritesRepository,
@Inject(DI.userNotePiningsRepository)
private userNotePiningsRepository: UserNotePiningsRepository,
@Inject(DI.db)
private db: DataSource,
private idService: IdService,
private queueLoggerService: QueueLoggerService,
@@ -37,12 +34,22 @@ export class CleanRemoteNotesProcessorService {
this.logger = this.queueLoggerService.logger.createSubLogger('clean-remote-notes');
}
@bindThis
private computeProgress(minId: string, maxId: string, cursorLeft: string) {
const minTs = this.idService.parse(minId).date.getTime();
const maxTs = this.idService.parse(maxId).date.getTime();
const cursorTs = this.idService.parse(cursorLeft).date.getTime();
return ((cursorTs - minTs) / (maxTs - minTs)) * 100;
}
@bindThis
public async process(job: Bull.Job<Record<string, unknown>>): Promise<{
deletedCount: number;
oldest: number | null;
newest: number | null;
skipped?: boolean;
skipped: boolean;
transientErrors: number;
}> {
if (!this.meta.enableRemoteNotesCleaning) {
this.logger.info('Remote notes cleaning is disabled, skipping...');
@@ -51,6 +58,7 @@ export class CleanRemoteNotesProcessorService {
oldest: null,
newest: null,
skipped: true,
transientErrors: 0,
};
}
@@ -59,7 +67,107 @@ export class CleanRemoteNotesProcessorService {
const maxDuration = this.meta.remoteNotesCleaningMaxProcessingDurationInMinutes * 60 * 1000; // Convert minutes to milliseconds
const startAt = Date.now();
const MAX_NOTE_COUNT_PER_QUERY = 50;
//#region queries
// The date limit for the newest note to be considered for deletion.
// All notes newer than this limit will always be retained.
const newestLimit = this.idService.gen(Date.now() - (1000 * 60 * 60 * 24 * this.meta.remoteNotesCleaningExpiryDaysForEachNotes));
// The condition for removing the notes.
// The note must be:
// - old enough (older than the newestLimit)
// - a remote note (userHost is not null).
// - not have clipped
// - not have pinned on the user profile
// - not has been favorite by any user
const removalCriteria = [
'note."id" < :newestLimit',
'note."clippedCount" = 0',
'note."pageCount" = 0',
'note."userHost" IS NOT NULL',
'NOT EXISTS (SELECT 1 FROM user_note_pining WHERE "noteId" = note."id")',
'NOT EXISTS (SELECT 1 FROM note_favorite WHERE "noteId" = note."id")',
'NOT EXISTS (SELECT 1 FROM note_reaction INNER JOIN "user" ON note_reaction."userId" = "user".id WHERE note_reaction."noteId" = note."id" AND "user"."host" IS NULL)',
].join(' AND ');
const minId = (await this.notesRepository.createQueryBuilder('note')
.select('MIN(note.id)', 'minId')
.where({
id: LessThan(newestLimit),
userHost: Not(IsNull()),
replyId: IsNull(),
renoteId: IsNull(),
})
.getRawOne<{ minId?: MiNote['id'] }>())?.minId;
if (!minId) {
this.logger.info('No notes can possibly be deleted, skipping...');
return {
deletedCount: 0,
oldest: null,
newest: null,
skipped: false,
transientErrors: 0,
};
}
// start with a conservative limit and adjust it based on the query duration
const minimumLimit = 10;
let currentLimit = 100;
let cursorLeft = '0';
const candidateNotesCteName = 'candidate_notes';
// tree walk down all root notes, short-circuit when the first unremovable note is found
const candidateNotesQueryBase = this.notesRepository.createQueryBuilder('note')
.select('note."id"', 'id')
.addSelect('note."replyId"', 'replyId')
.addSelect('note."renoteId"', 'renoteId')
.addSelect('note."id"', 'rootId')
.addSelect('TRUE', 'isRemovable')
.addSelect('TRUE', 'isBase')
.where('note."id" > :cursorLeft')
.andWhere(removalCriteria)
.andWhere({ replyId: IsNull(), renoteId: IsNull() });
const candidateNotesQueryInductive = this.notesRepository.createQueryBuilder('note')
.select('note.id', 'id')
.addSelect('note."replyId"', 'replyId')
.addSelect('note."renoteId"', 'renoteId')
.addSelect('parent."rootId"', 'rootId')
.addSelect(removalCriteria, 'isRemovable')
.addSelect('FALSE', 'isBase')
.innerJoin(candidateNotesCteName, 'parent', 'parent."id" = note."replyId" OR parent."id" = note."renoteId"')
.where('parent."isRemovable" = TRUE');
// A note tree can be deleted if there are no unremovable rows with the same rootId.
//
// `candidate_notes` will have the following structure after recursive query (some columns omitted):
// After performing a LEFT JOIN with `candidate_notes` as `unremovable`,
// the note tree containing unremovable notes will be anti-joined.
// For removable rows, the `unremovable` columns will have `NULL` values.
// | id | rootId | isRemovable |
// |-----|--------|-------------|
// | aaa | aaa | TRUE |
// | bbb | aaa | FALSE |
// | ccc | aaa | FALSE |
// | ddd | ddd | TRUE |
// | eee | ddd | TRUE |
// | fff | fff | TRUE |
// | ggg | ggg | FALSE |
//
const candidateNotesQuery = this.db.createQueryBuilder()
.select(`"${candidateNotesCteName}"."id"`, 'id')
.addSelect('unremovable."id" IS NULL', 'isRemovable')
.addSelect(`BOOL_OR("${candidateNotesCteName}"."isBase")`, 'isBase')
.addCommonTableExpression(
`((SELECT "base".* FROM (${candidateNotesQueryBase.orderBy('note.id', 'ASC').limit(currentLimit).getQuery()}) AS "base") UNION ${candidateNotesQueryInductive.getQuery()})`,
candidateNotesCteName,
{ recursive: true },
)
.from(candidateNotesCteName, candidateNotesCteName)
.leftJoin(candidateNotesCteName, 'unremovable', `unremovable."rootId" = "${candidateNotesCteName}"."rootId" AND unremovable."isRemovable" = FALSE`)
.groupBy(`"${candidateNotesCteName}"."id"`)
.addGroupBy('unremovable."id" IS NULL');
const stats = {
deletedCount: 0,
@@ -67,111 +175,107 @@ export class CleanRemoteNotesProcessorService {
newest: null as number | null,
};
// The date limit for the newest note to be considered for deletion.
// All notes newer than this limit will always be retained.
const newestLimit = this.idService.gen(Date.now() - (1000 * 60 * 60 * 24 * this.meta.remoteNotesCleaningExpiryDaysForEachNotes));
let cursor = '0'; // oldest note ID to start from
while (true) {
let lowThroughputWarned = false;
let transientErrors = 0;
for (;;) {
//#region check time
const batchBeginAt = Date.now();
// We use string literals instead of query builder for several reasons:
// - for removeCondition, we need to use it in having clause, which is not supported by Brackets.
// - for recursive part, we need to preserve the order of columns, but typeorm query builder does not guarantee the order of columns in the result query
const elapsed = batchBeginAt - startAt;
// The condition for removing the notes.
// The note must be:
// - old enough (older than the newestLimit)
// - a remote note (userHost is not null).
// - not have clipped
// - not have pinned on the user profile
// - not has been favorite by any user
const removeCondition = 'note.id < :newestLimit'
+ ' AND note."clippedCount" = 0'
+ ' AND note."userHost" IS NOT NULL'
// using both userId and noteId instead of just noteId to use index on user_note_pining table.
// This is safe because notes are only pinned by the user who created them.
+ ' AND NOT EXISTS(SELECT 1 FROM "user_note_pining" WHERE "noteId" = note."id" AND "userId" = note."userId")'
// We cannot use userId trick because users can favorite notes from other users.
+ ' AND NOT EXISTS(SELECT 1 FROM "note_favorite" WHERE "noteId" = note."id")'
;
// The initiator query contains the oldest ${MAX_NOTE_COUNT_PER_QUERY} remote non-clipped notes
const initiatorQuery = `
SELECT "note"."id" AS "id", "note"."replyId" AS "replyId", "note"."renoteId" AS "renoteId", "note"."id" AS "initiatorId"
FROM "note" "note" WHERE ${removeCondition} AND "note"."id" > :cursor ORDER BY "note"."id" ASC LIMIT ${MAX_NOTE_COUNT_PER_QUERY}`;
// The union query queries the related notes and replies related to the initiator query
const unionQuery = `
SELECT "note"."id", "note"."replyId", "note"."renoteId", rn."initiatorId"
FROM "note" "note"
INNER JOIN "related_notes" "rn"
ON "note"."replyId" = rn.id
OR "note"."renoteId" = rn.id
OR "note"."id" = rn."replyId"
OR "note"."id" = rn."renoteId"
`;
const recursiveQuery = `(${initiatorQuery}) UNION (${unionQuery})`;
const removableInitiatorNotesQuery = this.notesRepository.createQueryBuilder('note')
.select('rn."initiatorId"')
.innerJoin('related_notes', 'rn', 'note.id = rn.id')
.groupBy('rn."initiatorId"')
.having(`bool_and(${removeCondition})`);
const notesQuery = this.notesRepository.createQueryBuilder('note')
.addCommonTableExpression(recursiveQuery, 'related_notes', { recursive: true })
.select('note.id', 'id')
.addSelect('rn."initiatorId"')
.innerJoin('related_notes', 'rn', 'note.id = rn.id')
.where(`rn."initiatorId" IN (${ removableInitiatorNotesQuery.getQuery() })`)
.setParameters({ cursor, newestLimit });
const notes: { id: MiNote['id'], initiatorId: MiNote['id'] }[] = await notesQuery.getRawMany();
const fetchedCount = notes.length;
// update the cursor to the newest initiatorId found in the fetched notes.
// We don't use 'id' since the note can be newer than the initiator note.
for (const note of notes) {
if (cursor < note.initiatorId) {
cursor = note.initiatorId;
}
}
if (notes.length > 0) {
await this.notesRepository.delete(notes.map(note => note.id));
for (const note of notes) {
const t = this.idService.parse(note.id).date.getTime();
if (stats.oldest === null || t < stats.oldest) {
stats.oldest = t;
}
if (stats.newest === null || t > stats.newest) {
stats.newest = t;
}
}
stats.deletedCount += notes.length;
}
job.log(`Deleted ${notes.length} of ${fetchedCount}; ${Date.now() - batchBeginAt}ms`);
const elapsed = Date.now() - startAt;
const progress = this.computeProgress(minId, newestLimit, cursorLeft > minId ? cursorLeft : minId);
if (elapsed >= maxDuration) {
this.logger.info(`Reached maximum duration of ${maxDuration}ms, stopping...`);
job.log('Reached maximum duration, stopping cleaning.');
job.log(`Reached maximum duration of ${maxDuration}ms, stopping... (last cursor: ${cursorLeft}, final progress ${progress}%)`);
job.updateProgress(100);
break;
}
job.updateProgress((elapsed / maxDuration) * 100);
const wallClockUsage = elapsed / maxDuration;
if (wallClockUsage > 0.5 && progress < 50 && !lowThroughputWarned) {
const msg = `Not projected to finish in time! (wall clock usage ${wallClockUsage * 100}% at ${progress}%, current limit ${currentLimit})`;
this.logger.warn(msg);
job.log(msg);
lowThroughputWarned = true;
}
job.updateProgress(progress);
//#endregion
await setTimeout(1000 * 5); // Wait a moment to avoid overwhelming the db
const queryBegin = performance.now();
let noteIds = null;
try {
noteIds = await candidateNotesQuery.setParameters(
{ newestLimit, cursorLeft },
).getRawMany<{ id: MiNote['id'], isRemovable: boolean, isBase: boolean }>();
} catch (e) {
if (currentLimit > minimumLimit && e instanceof QueryFailedError && e.driverError?.code === '57014') {
// Statement timeout (maybe suddenly hit a large note tree), reduce the limit and try again
// continuous failures will eventually converge to currentLimit == minimumLimit and then throw
currentLimit = Math.max(minimumLimit, Math.floor(currentLimit * 0.25));
continue;
}
throw e;
}
if (noteIds.length === 0) {
job.log('No more notes to clean.');
break;
}
const queryDuration = performance.now() - queryBegin;
// try to adjust such that each query takes about 1~5 seconds and reasonable NodeJS heap so the task stays responsive
// this should not oscillate..
if (queryDuration > 5000 || noteIds.length > 5000) {
currentLimit = Math.floor(currentLimit * 0.5);
} else if (queryDuration < 1000 && noteIds.length < 1000) {
currentLimit = Math.floor(currentLimit * 1.5);
}
// clamp to a sane range
currentLimit = Math.min(Math.max(currentLimit, minimumLimit), 5000);
const deletableNoteIds = noteIds.filter(result => result.isRemovable).map(result => result.id);
if (deletableNoteIds.length > 0) {
try {
await this.notesRepository.delete(deletableNoteIds);
for (const id of deletableNoteIds) {
const t = this.idService.parse(id).date.getTime();
if (stats.oldest === null || t < stats.oldest) {
stats.oldest = t;
}
if (stats.newest === null || t > stats.newest) {
stats.newest = t;
}
}
stats.deletedCount += deletableNoteIds.length;
} catch (e) {
// check for integrity violation errors (class 23) that might have occurred between the check and the delete
// we can safely continue to the next batch
if (e instanceof QueryFailedError && e.driverError?.code?.startsWith('23')) {
transientErrors++;
job.log(`Error deleting notes: ${e} (transient race condition?)`);
} else {
throw e;
}
}
}
cursorLeft = noteIds.filter(result => result.isBase).reduce((max, { id }) => id > max ? id : max, cursorLeft);
job.log(`Deleted ${noteIds.length} notes; ${Date.now() - batchBeginAt}ms`);
if (process.env.NODE_ENV !== 'test') {
await setTimeout(Math.min(1000 * 5, queryDuration)); // Wait a moment to avoid overwhelming the db
}
};
if (transientErrors > 0) {
const msg = `${transientErrors} transient errors occurred while cleaning remote notes. You may need a second pass to complete the cleaning.`;
this.logger.warn(msg);
job.log(msg);
}
this.logger.succ('cleaning of remote notes completed.');
return {
@@ -179,6 +283,7 @@ export class CleanRemoteNotesProcessorService {
oldest: stats.oldest,
newest: stats.newest,
skipped: false,
transientErrors,
};
}
}
@@ -6,7 +6,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { MoreThan } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { DriveFilesRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
import type { DriveFilesRepository, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
import type Logger from '@/logger.js';
import { DriveService } from '@/core/DriveService.js';
import type { MiDriveFile } from '@/models/DriveFile.js';
@@ -14,6 +14,7 @@ import type { MiNote } from '@/models/Note.js';
import { EmailService } from '@/core/EmailService.js';
import { bindThis } from '@/decorators.js';
import { SearchService } from '@/core/SearchService.js';
import { PageService } from '@/core/PageService.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
import type { DbUserDeleteJobData } from '../types.js';
@@ -35,7 +36,11 @@ export class DeleteAccountProcessorService {
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
@Inject(DI.pagesRepository)
private pagesRepository: PagesRepository,
private driveService: DriveService,
private pageService: PageService,
private emailService: EmailService,
private queueLoggerService: QueueLoggerService,
private searchService: SearchService,
@@ -112,6 +117,28 @@ export class DeleteAccountProcessorService {
this.logger.succ('All of files deleted');
}
{
// delete pages. Necessary for decrementing pageCount of notes.
while (true) {
const pages = await this.pagesRepository.find({
where: {
userId: user.id,
},
take: 100,
order: {
id: 1,
},
});
if (pages.length === 0) {
break;
}
for (const page of pages) {
await this.pageService.delete(user, page.id);
}
}
}
{ // Send email notification
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
if (profile.email && profile.emailVerified) {
@@ -238,30 +238,6 @@ export class ServerService implements OnApplicationShutdown {
}
});
fastify.get<{ Params: { code: string } }>('/verify-email/:code', async (request, reply) => {
const profile = await this.userProfilesRepository.findOneBy({
emailVerifyCode: request.params.code,
});
if (profile != null) {
await this.userProfilesRepository.update({ userId: profile.userId }, {
emailVerified: true,
emailVerifyCode: null,
});
this.globalEventService.publishMainStream(profile.userId, 'meUpdated', await this.userEntityService.pack(profile.userId, { id: profile.userId }, {
schema: 'MeDetailed',
includeSecrets: true,
}));
reply.code(200).send('Verification succeeded! メールアドレスの認証に成功しました。');
return;
} else {
reply.code(404).send('Verification failed. Please try again. メールアドレスの認証に失敗しました。もう一度お試しください');
return;
}
});
fastify.register(this.clientServerService.createServer);
this.streamingApiServerService.attach(fastify.server);
@@ -176,6 +176,17 @@ export class ApiServerService {
}
});
fastify.all('/clear-browser-cache', (request, reply) => {
if (['GET', 'POST'].includes(request.method)) {
reply.header('Clear-Site-Data', '"cache", "prefetchCache", "prerenderCache", "executionContexts"');
reply.code(204);
reply.send();
} else {
reply.code(405);
reply.send();
}
});
// Make sure any unknown path under /api returns HTTP 404 Not Found,
// because otherwise ClientServerService will return the base client HTML
// page with HTTP 200.
@@ -412,6 +412,7 @@ export * as 'users/search' from './endpoints/users/search.js';
export * as 'users/search-by-username-and-host' from './endpoints/users/search-by-username-and-host.js';
export * as 'users/show' from './endpoints/users/show.js';
export * as 'users/update-memo' from './endpoints/users/update-memo.js';
export * as 'verify-email' from './endpoints/verify-email.js';
export * as 'chat/messages/create-to-user' from './endpoints/chat/messages/create-to-user.js';
export * as 'chat/messages/create-to-room' from './endpoints/chat/messages/create-to-room.js';
export * as 'chat/messages/delete' from './endpoints/chat/messages/delete.js';
@@ -34,13 +34,22 @@ export const meta = {
res: {
type: 'object',
optional: false, nullable: false,
ref: 'MeDetailed',
properties: {
token: {
type: 'string',
optional: false, nullable: false,
allOf: [
{
type: 'object',
ref: 'MeDetailed',
},
},
{
type: 'object',
optional: false, nullable: false,
properties: {
token: {
type: 'string',
optional: false, nullable: false,
},
},
}
],
},
} as const;
@@ -36,6 +36,7 @@ export const paramDef = {
startsAt: { type: 'integer' },
imageUrl: { type: 'string', minLength: 1 },
dayOfWeek: { type: 'integer' },
isSensitive: { type: 'boolean' },
},
required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl', 'dayOfWeek'],
} as const;
@@ -55,6 +56,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: new Date(ps.expiresAt),
startsAt: new Date(ps.startsAt),
dayOfWeek: ps.dayOfWeek,
isSensitive: ps.isSensitive,
url: ps.url,
imageUrl: ps.imageUrl,
priority: ps.priority,
@@ -73,6 +75,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: ad.expiresAt.toISOString(),
startsAt: ad.startsAt.toISOString(),
dayOfWeek: ad.dayOfWeek,
isSensitive: ad.isSensitive,
url: ad.url,
imageUrl: ad.imageUrl,
priority: ad.priority,
@@ -63,6 +63,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: ad.expiresAt.toISOString(),
startsAt: ad.startsAt.toISOString(),
dayOfWeek: ad.dayOfWeek,
isSensitive: ad.isSensitive,
url: ad.url,
imageUrl: ad.imageUrl,
memo: ad.memo,
@@ -39,6 +39,7 @@ export const paramDef = {
expiresAt: { type: 'integer' },
startsAt: { type: 'integer' },
dayOfWeek: { type: 'integer' },
isSensitive: { type: 'boolean' },
},
required: ['id'],
} as const;
@@ -66,6 +67,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : undefined,
startsAt: ps.startsAt ? new Date(ps.startsAt) : undefined,
dayOfWeek: ps.dayOfWeek,
isSensitive: ps.isSensitive,
});
const updatedAd = await this.adsRepository.findOneByOrFail({ id: ad.id });
@@ -49,6 +49,34 @@ export const meta = {
type: 'string',
optional: false, nullable: false,
},
icon: {
type: 'string',
optional: false, nullable: true,
},
display: {
type: 'string',
optional: false, nullable: false,
},
isActive: {
type: 'boolean',
optional: false, nullable: false,
},
forExistingUsers: {
type: 'boolean',
optional: false, nullable: false,
},
silence: {
type: 'boolean',
optional: false, nullable: false,
},
needConfirmationToRead: {
type: 'boolean',
optional: false, nullable: false,
},
userId: {
type: 'string',
optional: false, nullable: true,
},
imageUrl: {
type: 'string',
optional: false, nullable: true,
@@ -157,6 +157,22 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
maybeSensitive: {
type: 'boolean',
optional: false, nullable: false,
},
maybePorn: {
type: 'boolean',
optional: false, nullable: false,
},
requestIp: {
type: 'string',
optional: false, nullable: true,
},
requestHeaders: {
type: 'object',
optional: false, nullable: true,
},
},
},
} as const;
@@ -223,10 +223,12 @@ export const meta = {
sensitiveMediaDetection: {
type: 'string',
optional: false, nullable: false,
enum: ['none', 'all', 'local', 'remote'],
},
sensitiveMediaDetectionSensitivity: {
type: 'string',
optional: false, nullable: false,
enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'],
},
setSensitiveFlagAutomatically: {
type: 'boolean',
@@ -425,6 +427,10 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
clientOptions: {
type: 'object',
optional: false, nullable: false,
},
description: {
type: 'string',
optional: false, nullable: true,
@@ -469,6 +475,10 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
feedbackUrl: {
type: 'string',
optional: false, nullable: true,
},
summalyProxy: {
type: 'string',
optional: false, nullable: true,
@@ -650,6 +660,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
logoImageUrl: instance.logoImageUrl,
defaultLightTheme: instance.defaultLightTheme,
defaultDarkTheme: instance.defaultDarkTheme,
clientOptions: instance.clientOptions,
enableEmail: instance.enableEmail,
enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null,
@@ -48,8 +48,8 @@ export const paramDef = {
},
secret: {
type: 'string',
minLength: 1,
maxLength: 1024,
default: '',
},
},
required: [
@@ -57,7 +57,6 @@ export const paramDef = {
'name',
'on',
'url',
'secret',
],
} as const;
@@ -52,8 +52,8 @@ export const paramDef = {
},
secret: {
type: 'string',
minLength: 1,
maxLength: 1024,
default: '',
},
},
required: [
@@ -62,7 +62,6 @@ export const paramDef = {
'name',
'on',
'url',
'secret',
],
} as const;
@@ -67,6 +67,7 @@ export const paramDef = {
description: { type: 'string', nullable: true },
defaultLightTheme: { type: 'string', nullable: true },
defaultDarkTheme: { type: 'string', nullable: true },
clientOptions: { type: 'object', nullable: false },
cacheRemoteFiles: { type: 'boolean' },
cacheRemoteSensitiveFiles: { type: 'boolean' },
emailRequiredForSignup: { type: 'boolean' },
@@ -326,6 +327,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.defaultDarkTheme = ps.defaultDarkTheme;
}
if (ps.clientOptions !== undefined) {
set.clientOptions = ps.clientOptions;
}
if (ps.cacheRemoteFiles !== undefined) {
set.cacheRemoteFiles = ps.cacheRemoteFiles;
}
@@ -18,9 +18,9 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
import { ApiError } from '../../error.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { FetchAllowSoftFailMask } from '@/core/activitypub/misc/check-against-url.js';
import { ApiError } from '../../error.js';
export const meta = {
tags: ['federation'],
@@ -32,6 +32,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private chatService: ChatService,
) {
super(meta, paramDef, async (ps, me) => {
await this.chatService.checkChatAvailability(me.id, 'read');
await this.chatService.readAllChatMessages(me.id);
});
}

Some files were not shown because too many files have changed in this diff Show More