Compare commits

..

76 Commits

Author SHA1 Message Date
github-actions[bot] c803f842ba Bump version to 2025.5.1-alpha.0 2025-05-09 12:18:54 +00:00
syuilo b3f8ce60c6 New Crowdin updates (#16003)
* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Norwegian)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Russian)

* 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 Simplified)

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

* New translations ja-jp.yml (English)

* 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 (Japanese, Kansai)

* New translations ja-jp.yml (Korean (Gyeongsang))
2025-05-09 21:16:40 +09:00
かっこかり 04928ba7d1 enhance(frontend): Instance Tickerのデザイン改善 (#15946)
* feat(tms): インスタンス情報の表示位置 (taiyme#198)

* migrate

* fix(InstanceTicker): リモートサーバーのアイコンが初期画像になる問題 (taiyme#211)

* refactor(InstanceTicker): 参照の構造を変更

Co-Authored-By: taiy <53635909+taiyme@users.noreply.github.com>

* perf(TmsInstanceTicker): color関数に変更 (taiyme#283)

* 🎨

* Update Changelog

* remove unused property

* revert unrelated changes

* fix

* 実装を簡略化

* 🎨

* Update CHANGELOG.md

* 色の計算をコンポーネント内に移動

---------

Co-authored-by: taiy <53635909+taiyme@users.noreply.github.com>
2025-05-09 21:16:21 +09:00
syuilo 1b3a8cd97d fix(frontend): "時計"ウィジェット(Clock)において、Transparent設定が有効でも、その背景が透過されない
Fix #15994
2025-05-09 20:41:50 +09:00
syuilo bbe26607eb enhance: リプライ元にアンケートがあることが表示されるように
Resolve #15998
2025-05-09 20:36:14 +09:00
syuilo 6a2dc2d2d2 follow up of 8c2ab25e5f 2025-05-09 20:27:11 +09:00
syuilo 1febae7128 fix(backend): チャットルームが削除された場合・チャットルームから抜けた場合に、未読状態が残り続けることがあるのを修正 2025-05-09 20:12:33 +09:00
syuilo 2c63ab6fe3 New Crowdin updates (#15969)
* New translations ja-jp.yml (Chinese Simplified)

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

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

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Slovak)

* New translations ja-jp.yml (Ukrainian)

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

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

* New translations ja-jp.yml (English)

* 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 (Japanese, Kansai)
2025-05-09 19:42:04 +09:00
syuilo 96bc042d67 Feat: サーバー初期設定ウィザード (#15954)
* wip

* wip

* Update welcome.setup.vue

* wip

* wip

* wip

* wip

* Update MkServerSetupWizard.vue

* Update MkServerSetupWizard.vue

* wip

* wip

* wip

* Update types.ts

* wip

* wip

* Update CHANGELOG.md
2025-05-09 19:41:54 +09:00
anatawa12 0bd44bca6d fix: exported antenna data cannot be imported in some cases (#15985)
* chore: add ExportedAntenna type

* chore: use ExportedAntenna on export and fix schema

* fix: excludeNotesInSensitiveChannel is not included

* chore: revert unnecessary changes

* chore: add doc for future developer

* docs: update changelog
2025-05-09 17:48:01 +09:00
syuilo ebf291084f Feat: UGCの公開範囲設定機能 (#15938)
* wip

* Update CHANGELOG.md

* wip

* wip

* Update show.ts
2025-05-09 17:44:35 +09:00
syuilo 8c2ab25e5f Feat: No websocket mode (#15851)
* wip

* wip

* wip

* wip

* Update MkTimeline.vue

* wip

* wip

* wip

* Update MkTimeline.vue

* Update use-pagination.ts

* wip

* wip

* Update MkTimeline.vue

* Update MkTimeline.vue

* wip

* wip

* Update MkTimeline.vue

* Update MkTimeline.vue

* Update MkTimeline.vue

* wip

* Update use-pagination.ts

* wip

* Update use-pagination.ts

* Update MkNotifications.vue

* Update MkNotifications.vue

* wip

* wip

* wip

* Update use-note-capture.ts

* Update use-note-capture.ts

* Update use-note-capture.ts

* wip

* wip

* wip

* wip

* Update MkNoteDetailed.vue

* wip

* wip

* Update MkTimeline.vue

* wip

* fix

* Update MkTimeline.vue

* wip

* test

* Revert "test"

This reverts commit 3375619396.

* Update use-pagination.ts

* test

* Revert "test"

This reverts commit 42c53c830e.

* test

* Revert "test"

This reverts commit c4f8cda4aa.

* Update style.scss

* Update MkTimeline.vue

* Update MkTimeline.vue

* Update MkTimeline.vue

* ✌️

* Update MkTimeline.vue

* wip

* wip

* test

* Update MkPullToRefresh.vue

* Update MkPullToRefresh.vue

* Update MkPullToRefresh.vue

* Update MkPullToRefresh.vue

* Update MkTimeline.vue

* wip

* tweak navbar

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update home.vue

* wip

* refactor

* wip

* wip

* Update note.vue

* Update navbar.vue

* Update MkPullToRefresh.vue

* Update MkPullToRefresh.vue

* Update MkPullToRefresh.vue

* wip

* Update MkStreamingNotificationsTimeline.vue

* Update use-pagination.ts

* wip

* improve perf

* wip

* Update MkNotesTimeline.vue

* wip

* megre

* Update use-pagination.ts

* Update use-pagination.ts

* Update MkStreamingNotesTimeline.vue

* Update use-pagination.ts

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md
2025-05-09 17:40:08 +09:00
syuilo 5603cb7e22 refactor 2025-05-07 16:10:43 +09:00
syuilo 86996d9563 🎨 2025-05-07 13:41:51 +09:00
github-actions[bot] 978289535b [skip ci] Update CHANGELOG.md (prepend template) 2025-05-07 02:46:44 +00:00
github-actions[bot] aa938164f2 Release: 2025.5.0 2025-05-07 02:46:39 +00:00
syuilo 5c38589d03 Update CHANGELOG.md 2025-05-07 11:21:24 +09:00
syuilo 351d91b1c3 enhance(frontend): add debug room 2025-05-07 10:45:01 +09:00
syuilo 181f68e14e 🎨 2025-05-07 10:44:43 +09:00
syuilo cdd131d542 🎨 2025-05-07 08:55:42 +09:00
syuilo 921b13c26f 🎨 2025-05-06 21:49:10 +09:00
syuilo 5d787e5bb9 enhance(frontend): バックアップされた設定のプロファイルを削除できるように 2025-05-06 20:57:55 +09:00
syuilo 95a1d17cf6 🎨 2025-05-06 20:41:51 +09:00
github-actions[bot] 14955fa01f Bump version to 2025.5.0-rc.0 2025-05-06 11:28:09 +00:00
syuilo 0f922cda54 New Crowdin updates (#15949)
* New translations ja-jp.yml (Catalan)

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

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Russian)
2025-05-06 20:15:42 +09:00
anatawa12 406406328c Fix 1745378064470-composite-note-index.js (#15968) 2025-05-06 20:15:26 +09:00
おさむのひと 29f9580143 fix: developのtypecheckエラーを修正 (#15967) 2025-05-06 19:59:24 +09:00
zyoshoka 3b676f39df fix(backend): enumerate achievement types in some response schema (#15953)
* fix(backend): enumerate achievement types in some response schema

* refactor: use `ref`
2025-05-06 19:52:30 +09:00
syuilo 09317150e1 add icon project file 2025-05-06 16:53:06 +09:00
syuilo 925dd76f00 🎨 2025-05-06 16:51:01 +09:00
syuilo 1d79fc9092 🎨 2025-05-06 16:16:22 +09:00
syuilo 8959bfa1c0 refactor(frontend): 空/エラー結果表示をコンポーネント化 (#15963)
* wip

* wip

* wip

* wip

* wip

* Update MkResult.vue

* Add storybook story for MkResult (#15964)

* Update MkResult.vue

---------

Co-authored-by: taichan <40626578+tai-cha@users.noreply.github.com>
2025-05-06 14:41:31 +09:00
Kisaragi d476f7ff50 chore(deps): sharpを固定 (#15957)
cf. misskey-dev#15920
2025-05-05 20:00:42 +09:00
github-actions[bot] f251ca8303 Bump version to 2025.5.0-beta.0 2025-05-05 09:31:57 +00:00
syuilo f6158abb68 use sharp 0.33.5
Fix #15920
2025-05-05 18:23:25 +09:00
syuilo fc2e128fad tweak ui style 2025-05-05 18:20:55 +09:00
github-actions[bot] 45d6c090f2 Bump version to 2025.5.0-alpha.2 2025-05-05 05:41:19 +00:00
かっこかり 57a1ac3dd0 fix(frontend): 横スワイプの挙動改善 (#15952) 2025-05-05 14:28:54 +09:00
syuilo 6bbda4d67c fix(frontend): make enableHorizontalSwipe default false 2025-05-05 07:28:15 +09:00
zyoshoka 32d2206832 fix(frontend): handle error in user popup (#15948) 2025-05-05 06:04:20 +09:00
Sayamame-beans d522d1bf26 docs(changelog): add information for #15924 (#15947) 2025-05-04 20:59:24 +09:00
github-actions[bot] 080276e3e7 Bump version to 2025.5.0-alpha.1 2025-05-04 10:07:59 +00:00
syuilo 619bb2214e New Crowdin updates (#15935)
* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Catalan)

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

* New translations ja-jp.yml (English)
2025-05-04 19:00:56 +09:00
renovate[bot] c23f2ff900 chore(deps): update node.js to v22.15.0 (#15606)
* chore(deps): update node.js to v22.15.0

* chore: determine Jest args from Node.js version

* fix

* fix: `import.meta.dirname` is not supported in v20.10.0

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
2025-05-04 19:00:36 +09:00
syuilo 14d6734cb1 Fix MkPullToRefresh behaviour (#15944)
* Update MkPullToRefresh.vue

* Update MkPullToRefresh.vue

* Update MkPullToRefresh.vue
2025-05-04 18:51:30 +09:00
syuilo 3bdb1dd558 🎨 2025-05-04 17:32:09 +09:00
かっこかり e75d749784 fix(frontend): ダイアログのお知らせが画面からはみ出ることがある問題を修正 (#15878)
* fix(frontend): ダイアログのお知らせが画面からはみ出ることがある問題を修正

* Update Changelog

* 🎨

* 🎨

* enhance: スクロールしないと閉じられないように

* Update CHANGELOG.md
2025-05-04 15:50:05 +09:00
renovate[bot] 42a2ed8b67 fix(deps): update dependency vite to v6.3.4 [security] (#15918)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-04 14:54:35 +09:00
zyoshoka a5fa9a2cef chore(workflow): use node-version-file instead of hardcoded node-version (#15658)
* chore(workflow): use `node-version-file` instead of hardcoded `node-version`

* chore: test min version
2025-05-04 14:14:09 +09:00
かっこかり 0884605b62 fix(frontend): MkFolderのアニメーションにフォールバックを追加 (#15937)
* fix(frontend): Chrome系以外のブラウザでMkFolderがアニメーションしない問題を修正

* fix

* Update Changelog

* fix
2025-05-04 14:06:43 +09:00
かっこかり 8dbd8ff4cf enhance(frontend): タイムラインpush時のアニメーションを調整 (#15936)
* fix(frontend): タイムラインpush時のアニメーションを復元

* 🎨

* enhance: 消える際のアニメーションも追加

* better support for non-supported browsers

* fix: Skip Note Rendering有効時、TransitionGroupでnoteを追加するときに一瞬がくっとなる問題を修正

* 🎨

* fix
2025-05-04 13:52:01 +09:00
syuilo 5aeedf59ff enhance(frontend): 中クリックでPullToRefreshするように
Close #15931
2025-05-04 11:04:51 +09:00
github-actions[bot] 3eaa05a5d9 Bump version to 2025.5.0-alpha.0 2025-05-04 00:41:28 +00:00
syuilo b0b6962661 New Crowdin updates (#15922)
* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (English)

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

* 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 (German)

* New translations ja-jp.yml (English)
2025-05-04 09:40:06 +09:00
おさむのひと 8c0c503c6c refactor: ファイルアップロード時のテストを追加 (#15928)
* refactor: ファイルアップロード時のテストを追加

* なぜかsemverが消えてた
2025-05-04 09:38:35 +09:00
syuilo 590cb5f4dd perf(frontend): improve MkInstanceTicker rendering performance 2025-05-04 06:43:53 +09:00
syuilo 90e69f4d10 add note 2025-05-03 21:51:58 +09:00
syuilo e76e2534d7 perf(frontend): improve MkPullToRefresh render performance 2025-05-03 21:40:18 +09:00
syuilo 27682b980c tweak MkPullToRefresh.vue 2025-05-03 21:14:59 +09:00
syuilo ef79cc290f perf(frontend): tweak PageWithHeader 2025-05-03 20:15:18 +09:00
syuilo e7c170cf0c tweak MkPullToRefresh 2025-05-03 18:35:43 +09:00
syuilo f0544ede87 tweak MkPullToRefresh 2025-05-03 16:51:23 +09:00
syuilo 00008d3763 Update CHANGELOG.md 2025-05-03 16:25:09 +09:00
おさむのひと 526057cc61 Revert "fix: 添付ファイルのあるリクエストを受けたときの初動を改善 (#15896)" (#15927)
* Revert "fix: 添付ファイルのあるリクエストを受けたときの初動を改善 (#15896)"

This reverts commit 7e8cc4d7c0.

* fix CHANGELOG.md
2025-05-03 16:23:06 +09:00
おさむのひと c13aa0c224 fix(backend): チャンネルフォロー一覧のsinceId/untilIdによる絞り込みが上手く動いていないのを修正 (#13698)
* fix(backend): チャンネルフォロー一覧のsinceId/untilIdによる絞り込みが上手く動いていないのを修正

* fix CHANGELOG.md

* docs(changelog): fix mistaken changelog insertion (restore newline)

* docs(changelog): update insertion position

---------

Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
2025-05-03 15:40:57 +09:00
anatawa12 1af98b690b feat: CREATE INDEX CONCURRENTLY for "userId" "id" composite note index if admin wish. (#15915)
* chore: CREATE INDEX CONCURRENTLY for "userId" "id" composite note index

* chore: remove { concurrent: true } and comment why

* update comment

* feat: add MISSKEY_MIGRATION_CREATE_INDEX_CONCURRENTLY option

* fix: spdx license header

* alter comment

* chore: improve behavior when migration failure

* docs(changelog): 2025.4.1 で追加されたインデックスの再生成をノートの追加しながら行えるようになりました

* ちょっと表現を変更

---------

Co-authored-by: 饺子w (Yumechi) <35571479+eternal-flame-ad@users.noreply.github.com>
2025-05-03 12:57:50 +09:00
syuilo d25af911cf fix(frontend): tweak universal ui rendering 2025-05-03 11:19:55 +09:00
syuilo df1a3742dd feat(frontend): マウスでもタイムラインを引っ張って更新できるように & MkPullToRefreshのパフォーマンス向上 2025-05-03 10:26:40 +09:00
syuilo c5235a7b2f perf(frontend): improve timeline page performance 2025-05-02 20:25:51 +09:00
anatawa12 795b8366b5 Block deliver by software (#15727)
* feat(backend): suspend instance by software

* feat(frontend): suspend instance by software

* docs(chaangelog): 連合先のソフトウェア及びバージョン名により配信停止を行えるようになりました

* chore: 例で使うバージョン名を変える

* fix: broken lockfile

* fix: broken lock file

* fix broken lock file

* update changelog

* fix dependencies

* Update CHANGELOG.md

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-05-01 17:58:34 +09:00
anatawa12 2fcb50273d Exclude suspended users note from most timelines (#15775)
* feat: exclude notes by suspended user from FTT timeline endpoint

* feat: exclude notes by suspended user from DB based timelines

* chore: fix types

* chore: fix types

* chore: fix non-reply / renote

* chore: fix non-reply / renote

* test: update test

* docs(changelog): 凍結されたユーザのノートが各種タイムラインで表示されないように

* Exclude suspended users note from featured

* fix: join user

* Update CHANGELOG.md

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-05-01 17:56:24 +09:00
github-actions[bot] 70232d3d73 [skip ci] Update CHANGELOG.md (prepend template) 2025-04-30 09:01:49 +00:00
github-actions[bot] 979cfc1bcd Release: 2025.4.1 2025-04-30 09:01:43 +00:00
github-actions[bot] 2bd4faafbc Bump version to 2025.4.1-rc.0 2025-04-30 00:15:24 +00:00
zyoshoka 81739b1f82 chore: follow up on fixing Chromatic CI diff strategy (#15912) 2025-04-29 21:22:01 +09:00
Julia 583df3ec63 Merge commit from fork
none of our endpoints will ever contain `..` (they might, maybe, at
some point, contain `.`, as in `something/get.html`?), so every
`Mk:api()` call to an endpoint that contains `..` can't work: let's
reject it outright

Co-authored-by: dakkar <dakkar@thenautilus.net>
2025-04-29 18:06:39 +09:00
271 changed files with 5355 additions and 3293 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "22.11.0"
"version": "22.15.0"
},
"ghcr.io/devcontainers-extra/features/pnpm:2": {
"version": "10.10.0"
+1
View File
@@ -0,0 +1 @@
20.10.0
+2 -3
View File
@@ -17,7 +17,6 @@ jobs:
strategy:
matrix:
node-version: [22.11.0]
api-json-name: [api-base.json, api-head.json]
include:
- api-json-name: api-base.json
@@ -32,10 +31,10 @@ jobs:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
+2 -7
View File
@@ -15,22 +15,17 @@ jobs:
contents: read
id-token: write
strategy:
matrix:
node-version: [22.11.0]
steps:
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: '.node-version'
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
- name: Publish package
run: |
pnpm i --frozen-lockfile
+2 -2
View File
@@ -38,7 +38,7 @@ jobs:
run: git checkout "$(git rev-list --parents -n1 HEAD | cut -d" " -f3)"
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js 20.x
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
@@ -78,7 +78,7 @@ jobs:
if: github.event_name == 'pull_request_target'
id: chromatic_pull_request
run: |
CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r origin/${GITHUB_BASE_REF}...origin/${GITHUB_HEAD_REF} | xargs))"
CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff --name-only origin/${GITHUB_BASE_REF}...origin/${GITHUB_HEAD_REF} | xargs))"
if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
fi
+10 -8
View File
@@ -22,10 +22,11 @@ jobs:
unit:
name: Unit tests (backend)
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
node-version-file:
- .node-version
- .github/min.node-version
services:
postgres:
@@ -61,10 +62,10 @@ jobs:
exit 1
fi
done
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: ${{ matrix.node-version-file }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
@@ -84,10 +85,11 @@ jobs:
e2e:
name: E2E tests (backend)
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
node-version-file:
- .node-version
- .github/min.node-version
services:
postgres:
@@ -108,10 +110,10 @@ jobs:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: ${{ matrix.node-version-file }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
+6 -3
View File
@@ -21,7 +21,9 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
node-version-file:
- .node-version
- .github/min.node-version
steps:
- uses: actions/checkout@v4
with:
@@ -43,10 +45,10 @@ jobs:
exit 1
fi
done
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: ${{ matrix.node-version-file }}
cache: 'pnpm'
- name: Build Misskey
run: |
@@ -54,6 +56,7 @@ jobs:
pnpm build
- name: Setup
run: |
echo "NODE_VERSION=$(cat ${{ matrix.node-version-file }})" >> $GITHUB_ENV
cd packages/backend/test-federation
bash ./setup.sh
sudo chmod 644 ./certificates/*.test.key
+4 -9
View File
@@ -27,20 +27,16 @@ jobs:
name: Unit tests (frontend)
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
steps:
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
@@ -64,7 +60,6 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [22.11.0]
browser: [chrome]
services:
@@ -92,10 +87,10 @@ jobs:
# if: ${{ matrix.browser == 'firefox' }}
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Copy Configure
+2 -7
View File
@@ -20,11 +20,6 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
@@ -32,10 +27,10 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Setup Node.js ${{ matrix.node-version }}
- name: Setup Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: '.node-version'
cache: 'pnpm'
- name: Install dependencies
+2 -6
View File
@@ -15,20 +15,16 @@ jobs:
name: Production build
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
steps:
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
+2 -6
View File
@@ -16,20 +16,16 @@ jobs:
validate-api-json:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
steps:
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
node-version-file: '.node-version'
cache: 'pnpm'
- name: Install Redocly CLI
run: npm i -g @redocly/cli
+1 -1
View File
@@ -1 +1 @@
22.11.0
22.15.0
+57
View File
@@ -1,3 +1,60 @@
## 2025.5.1
### General
- Feat: 非ログインでサーバーを閲覧された際に、サーバー内のコンテンツを非公開にすることができるようになりました
- モデレーションが行き届きにくい不適切なリモートコンテンツなどが、自サーバー経由で図らずもインターネットに公開されてしまうことによるトラブル防止などに役立ちます
- 「全て公開(今までの挙動)」「ローカルのコンテンツだけ公開(=サーバー内で受信されたリモートのコンテンツは公開しない)」「何も公開しない」から選択できます
- デフォルト値は「ローカルのコンテンツだけ公開」になっています
### Client
- Feat: サーバー初期設定ウィザードが実装されました
- 簡単なウィザードに従うだけで、サーバーに最適な設定が適用されます
- Feat: Websocket接続を行わずにMisskeyを利用するNo Websocketモードが実装されました(beta)
- サーバーのパフォーマンス向上に寄与することが期待されます
- 何らの理由によりWebsocket接続が行えない環境でも快適に利用可能です
- 従来のWebsocket接続を行うモードはリアルタイムモードとして再定義されました
- チャットなど、一部の機能は引き続き設定に関わらずWebsocket接続が行われます
- Enhance: メモリ使用量を軽減しました
- Enhance: リプライ元にアンケートがあることが表示されるように
- Enhance: ノートのサーバー情報のデザインを改善・パフォーマンス向上
(Based on https://github.com/taiyme/misskey/pull/198, https://github.com/taiyme/misskey/pull/211, https://github.com/taiyme/misskey/pull/283)
- Fix: "時計"ウィジェット(Clock)において、Transparent設定が有効でも、その背景が透過されない問題を修正
### Server
- Enhance: ノートのレスポンスにアンケートが添付されているかどうかを示すフラグ`hasPoll`を追加
- Fix: チャットルームが削除された場合・チャットルームから抜けた場合に、未読状態が残り続けることがあるのを修正
- Fix: ユーザ除外アンテナをインポートできない問題を修正
- Fix: アンテナのセンシティブなチャンネルのノートを含むかどうかの情報がエクスポートされない問題を修正
## 2025.5.0
### Note
- DockerのNode.jsが22.15.0に更新されました
### Client
- Feat: マウスで中ボタンドラッグによりタイムラインを引っ張って更新できるように
- アクセシビリティ設定からオフにすることもできます
- Enhance: タイムラインのパフォーマンスを向上
- Enhance: バックアップされた設定のプロファイルを削除できるように
- Fix: 一部のブラウザでアコーディオンメニューのアニメーションが動作しない問題を修正
- Fix: ダイアログのお知らせが画面からはみ出ることがある問題を修正
- Fix: ユーザーポップアップでエラーが生じてもインジケーターが表示され続けてしまう問題を修正
### Server
- Enhance: 凍結されたユーザのノートが各種タイムラインで表示されないように `#15775`
- Enhance: 連合先のソフトウェア及びバージョン名により配信停止を行えるように `#15727`
- Enhance: 2025.4.1 で追加されたインデックスの再生成をノートの追加しながら行えるようになりました。 `#15915`
- `MISSKEY_MIGRATION_CREATE_INDEX_CONCURRENTLY` 環境変数を `1` にセットしていると、巨大なテーブルの既存のカラムに関するインデックス再生成が`CREATE INDEX CONCURRENTLY`を使用するようになりました。
- 複数のサーバープロセスをクラスタリングしているサーバーにおいて、一部のプロセスが起動している状態でこのオプションを有効にしてマイグレーションすることにより、ダウンタイムを削減することができます。
- ただし、このオプションを有効にする場合、インデックスの作成にかかる時間が倍~3倍以上になることがあります。
- また、大きなインスタンスである場合にはインデックスの作成に失敗し、複数回再試行する必要がある可能性があります。
- Fix: チャンネルのフォロー一覧の結果が一部正しくないのを修正 (#12175)
- Fix: ファイルをアップロードした際にファイル名が常に untitled になる問題を修正
- Fix: ファイルのアップロードに失敗することがある問題を修正
- 投稿フォーム上で画像のクロップを行うと、`Invalid Param.`エラーでノートが投稿出来なくなる問題も解決されます。
- この事象によって既にノートが投稿出来ない状態になっている場合は、投稿フォーム右上のメニューから、下書きデータの「リセット」を行ってください。
## 2025.4.1
### General
+1 -1
View File
@@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.4
ARG NODE_VERSION=22.11.0-bookworm
ARG NODE_VERSION=22.15.0-bookworm
# build assets & compile TypeScript
Binary file not shown.
-5
View File
@@ -2,11 +2,6 @@ import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:61812',
},
})
+9
View File
@@ -31,6 +31,15 @@ describe('Before setup instance', () => {
// なぜか動かない
//cy.wait('@signup').should('have.property', 'response.statusCode');
cy.wait('@signup');
cy.intercept('POST', '/api/admin/update-meta').as('update-meta');
cy.get('[data-cy-next]').click();
cy.get('[data-cy-next]').click();
cy.get('[data-cy-server-name] input').type('Testskey');
cy.get('[data-cy-server-setup-wizard-apply]').click();
cy.wait('@update-meta');
});
});
-22
View File
@@ -1,22 +0,0 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
-2
View File
@@ -215,7 +215,6 @@ noUsers: "ليس هناك مستخدمون"
editProfile: "تعديل الملف التعريفي"
noteDeleteConfirm: "هل تريد حذف هذه الملاحظة؟"
pinLimitExceeded: "لا يمكنك تثبيت الملاحظات بعد الآن."
intro: "لقد انتهت عملية تنصيب Misskey. الرجاء إنشاء حساب إداري."
done: "تمّ"
processing: "المعالجة جارية"
preview: "معاينة"
@@ -676,7 +675,6 @@ experimental: "اختباري"
developer: "المطور"
makeExplorable: "أظهر الحساب في صفحة \"استكشاف\""
makeExplorableDescription: "بتعطيل هذا الخيار لن يظهر حسابك في صفحة \"استكشاف\""
showGapBetweenNotesInTimeline: "أظهر فجوات بين المشاركات في الخيط الزمني"
left: "يسار"
center: "وسط"
wide: "عريض"
-2
View File
@@ -215,7 +215,6 @@ noUsers: "কোন ব্যাবহারকারী নেই"
editProfile: "প্রোফাইল সম্পাদনা করুন"
noteDeleteConfirm: "আপনি কি নোট ডিলিট করার ব্যাপারে নিশ্চিত?"
pinLimitExceeded: "আপনি আর কোন নোট পিন করতে পারবেন না"
intro: "Misskey এর ইন্সটলেশন সম্পন্ন হয়েছে!দয়া করে অ্যাডমিন ইউজার তৈরি করুন।"
done: "সম্পন্ন"
processing: "প্রক্রিয়াধীন..."
preview: "পূর্বরূপ দেখুন"
@@ -673,7 +672,6 @@ experimentalFeatures: "পরীক্ষামূলক বৈশিষ্ট
developer: "ডেভেলপার"
makeExplorable: "অ্যাকাউন্ট \"ঘুরে দেখুন\" পৃষ্ঠায় দেখান"
makeExplorableDescription: "আপনি এটি বন্ধ করলে, আপনার অ্যাকাউন্ট \"ঘুরে দেখুন\" পৃষ্ঠায় প্রদর্শিত হবে না।"
showGapBetweenNotesInTimeline: "টাইমলাইন এবং নোটের মাঝে ফাকা জায়গা রাখুন"
duplicate: "প্রতিরূপ"
left: "বাম"
center: "মাঝখান"
+8 -3
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "Silencia aquesta instància "
mediaSilenceThisInstance: "Silenciar els arxius d'aquesta instància "
operations: "Accions"
software: "Programari"
softwareName: "Nom del programari"
version: "Versió"
metadata: "Metadades"
withNFiles: "{n} fitxer(s)"
@@ -250,7 +251,6 @@ noUsers: "No hi ha usuaris"
editProfile: "Edita el perfil"
noteDeleteConfirm: "Segur que voleu eliminar aquesta publicació?"
pinLimitExceeded: "No podeu fixar més publicacions"
intro: "La instal·lació de Misskey ha acabat! Crea un usuari d'administrador."
done: "Fet"
processing: "S'està processant..."
preview: "Vista prèvia"
@@ -784,7 +784,6 @@ thisIsExperimentalFeature: "Aquesta és una característica experimental. La sev
developer: "Programador"
makeExplorable: "Fes que el compte sigui visible a la secció \"Explorar\""
makeExplorableDescription: "Si desactives aquesta opció, el teu compte no sortirà a la secció \"Explorar\""
showGapBetweenNotesInTimeline: "Notes separades a la línia de temps"
duplicate: "Duplicat"
left: "Esquerra"
center: "Centre"
@@ -1237,7 +1236,6 @@ showAvatarDecorations: "Mostrar les decoracions dels avatars"
releaseToRefresh: "Deixar anar per actualitzar"
refreshing: "Recarregant..."
pullDownToRefresh: "Llisca cap a baix per recarregar"
disableStreamingTimeline: "Desactivar l'actualització en temps real de les línies de temps"
useGroupedNotifications: "Mostrar les notificacions agrupades "
signupPendingError: "Hi ha hagut un problema verificant l'adreça de correu electrònic. L'enllaç pot haver caducat."
cwNotationRequired: "Si està activat \"Amagar contingut\" s'ha d'escriure una descripció "
@@ -1347,6 +1345,7 @@ readonly: "Només lectura"
goToDeck: "Tornar al tauler"
federationJobs: "Treballs sindicats "
driveAboutTip: "Al Disc veure's una llista de tots els arxius que has anat pujant.<br>\nPots tornar-los a fer servir adjuntant-los a notes noves o pots adelantar-te i pujar arxius per publicar-los més tard!<br>\n<b>Tingués en compte que si esborres un arxiu també desapareixerà de tots els llocs on l'has fet servir (notes, pàgines, avatars, imatges de capçalera, etc.)</b><br>\nTambé pots crear carpetes per organitzar les."
scrollToClose: "Desplaçar per tancar"
_chat:
noMessagesYet: "Encara no tens missatges "
newMessage: "Missatge nou"
@@ -1423,6 +1422,8 @@ _settings:
ifOn: "Quan s'activa"
ifOff: "Quan es desactiva"
enableSyncThemesBetweenDevices: "Sincronitzar els temes instal·lats entre dispositius"
enablePullToRefresh: "Lliscar i actualitzar "
enablePullToRefresh_description: "Amb el ratolí, llisca mentre prems la roda."
_chat:
showSenderName: "Mostrar el nom del remitent"
sendOnEnter: "Introdueix per enviar"
@@ -1430,6 +1431,7 @@ _preferencesProfile:
profileName: "Nom del perfil"
profileNameDescription: "Estableix un nom que identifiqui aquest dispositiu."
profileNameDescription2: "Per exemple: \"PC Principal\", \"Smartphone\", etc"
manageProfiles: "Gestionar perfils"
_preferencesBackup:
autoBackup: "Còpia de seguretat automàtica "
restoreFromBackup: "Restaurar des d'una còpia de seguretat"
@@ -1468,6 +1470,7 @@ _delivery:
manuallySuspended: "Suspendre manualment"
goneSuspended: "Servidor suspès perquè el servidor s'ha esborrat"
autoSuspendedForNotResponding: "Servidor suspès perquè el servidor no respon"
softwareSuspended: "Suspès perquè el programari ha deixat de desenvolupar-se "
_bubbleGame:
howToPlay: "Com es juga"
hold: "Mantenir"
@@ -1599,6 +1602,8 @@ _serverSettings:
openRegistration: "Registres oberts"
openRegistrationWarning: "Obrir els registres és arriscat. Es recomana obrir-los només si el servidor és monitorat constantment i per respondre immediatament davant qualsevol problema."
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Si no es detecta activitat per part del moderador durant un període de temps, aquesta opció es desactiva automàticament per evitar el correu brossa."
deliverSuspendedSoftware: "Programari que ja no es distribueix"
deliverSuspendedSoftwareDescription: "Pots especificar un rang de noms i versions del programari del servidor per detenir l'entrega, per exemple, degut a vulnerabilitats. Aquesta informació la proporciona el servidor i la seva fiabilitat no es garantitzada. Es pot fer servir una especificació de rang sencer per especificar una versió, però es recomana especificar una versió anterior, com >= 2024.3.1-0, perquè especificar >= 2024.3.1 no incloure versions personalitzades com 2024.3.1-custom.0."
_accountMigration:
moveFrom: "Migrar un altre compte a aquest"
moveFromSub: "Crear un àlies per un altre compte"
-2
View File
@@ -228,7 +228,6 @@ noUsers: "Žádní uživatelé"
editProfile: "Upravit můj profil"
noteDeleteConfirm: "Jste si jistí že chcete smazat tuhle poznámku?"
pinLimitExceeded: "Nemůžete připnout další poznámky."
intro: "Instalace Misskey byla dokončena! Prosím vytvořte admina."
done: "Hotovo"
processing: "Zpracovávám"
preview: "Náhled"
@@ -726,7 +725,6 @@ thisIsExperimentalFeature: "Tohle je experimentální funkce. Její funkce se m
developer: "Vývojář"
makeExplorable: "Udělat účet viditelný v \"Objevit\""
makeExplorableDescription: "Pokud tohle vypnete, tak se účet přestane zobrazovat v sekci \"Objevit\"."
showGapBetweenNotesInTimeline: "Zobrazit mezeru mezi příspěvkama na časové ose"
duplicate: "Duplikovat"
left: "Vlevo"
center: "Uprostřed"
+8 -3
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "Instanz stummschalten"
mediaSilenceThisInstance: "Medien dieses Servers stummschalten"
operations: "Aktionen"
software: "Software"
softwareName: "Software Name"
version: "Version"
metadata: "Metadaten"
withNFiles: "{n} Datei(en)"
@@ -250,7 +251,6 @@ noUsers: "Keine Benutzer gefunden"
editProfile: "Profil bearbeiten"
noteDeleteConfirm: "Möchtest du diese Notiz wirklich löschen?"
pinLimitExceeded: "Du kannst nicht noch mehr Notizen anheften."
intro: "Misskey ist installiert! Lass uns nun ein Administratorkonto einrichten."
done: "Fertig"
processing: "In Bearbeitung …"
preview: "Vorschau"
@@ -784,7 +784,6 @@ thisIsExperimentalFeature: "Dies ist eine experimentelle Funktion. Änderungen a
developer: "Entwickler"
makeExplorable: "Benutzerkonto in „Erkunden“ sichtbar machen"
makeExplorableDescription: "Wenn diese Option deaktiviert ist, ist dein Benutzerkonto nicht im „Erkunden“-Bereich sichtbar."
showGapBetweenNotesInTimeline: "Abstände zwischen Notizen auf der Chronik anzeigen"
duplicate: "Duplizieren"
left: "Links"
center: "Mittig"
@@ -1237,7 +1236,6 @@ showAvatarDecorations: "Profilbilddekoration anzeigen"
releaseToRefresh: "Zum Aktualisieren loslassen"
refreshing: "Wird aktualisiert..."
pullDownToRefresh: "Zum Aktualisieren ziehen"
disableStreamingTimeline: "Echtzeitaktualisierung der Chronik deaktivieren"
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."
@@ -1347,6 +1345,7 @@ readonly: "Nur Lesezugriff"
goToDeck: "Zurück zum Deck"
federationJobs: "Föderation Jobs"
driveAboutTip: "In Drive sehen Sie eine Liste der Dateien, die Sie in der Vergangenheit hochgeladen haben. <br>\nSie können diese Dateien wiederverwenden um sie zu beispiel an Notizen anzuhängen, oder sie können Dateien vorab hochzuladen, um sie später zu versenden! <br>\n<b>Wenn Sie eine Datei löschen, verschwindet sie auch von allen Stellen, an denen Sie sie verwendet haben (Notizen, Seiten, Avatare, Banner usw.).</b><br>\nSie können auch Ordner erstellen, um sie zu organisieren."
scrollToClose: "Zum Schließen scrollen"
_chat:
noMessagesYet: "Noch keine Nachrichten"
newMessage: "Neue Nachricht"
@@ -1423,6 +1422,8 @@ _settings:
ifOn: "Wenn eingeschaltet"
ifOff: "Wenn ausgeschaltet"
enableSyncThemesBetweenDevices: "Synchronisierung von installierten Themen auf verschiedenen Endgeräten"
enablePullToRefresh: "Ziehen zum Aktualisieren"
enablePullToRefresh_description: "Bei Benutzung einer Maus, mit gedrücktem Mausrad ziehen"
_chat:
showSenderName: "Name des Absenders anzeigen"
sendOnEnter: "Eingabetaste sendet Nachricht"
@@ -1430,6 +1431,7 @@ _preferencesProfile:
profileName: "Profilname"
profileNameDescription: "Lege einen Namen fest, der dieses Gerät identifiziert."
profileNameDescription2: "Beispiel: \"Haupt-PC\", \"Smartphone\""
manageProfiles: "Profile verwalten"
_preferencesBackup:
autoBackup: "Automatische Sicherung"
restoreFromBackup: "Wiederherstellen aus der Sicherung"
@@ -1468,6 +1470,7 @@ _delivery:
manuallySuspended: "Manuell gesperrt"
goneSuspended: "Gesperrt wegen Löschung des Servers"
autoSuspendedForNotResponding: "Gesperrt, weil der Server nicht antwortet"
softwareSuspended: "Ausgesetzt, weil die Software nicht mehr beliefert wird"
_bubbleGame:
howToPlay: "Wie man spielt"
hold: "Halten"
@@ -1599,6 +1602,8 @@ _serverSettings:
openRegistration: "Registrierung von Konten aktivieren"
openRegistrationWarning: "Das Aktivieren von Registrierungen ist riskant. Es wird empfohlen, sie nur dann zu aktivieren, wenn der Server ständig überwacht wird und im Falle eines Problems sofort reagiert werden kann."
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Wenn über einen bestimmten Zeitraum keine Moderatorenaktivität festgestellt wird, wird diese Einstellung automatisch deaktiviert, um Spam zu verhindern."
deliverSuspendedSoftware: "Software, die nicht mehr beliefert wird"
deliverSuspendedSoftwareDescription: "Sie können eine Auswahl von Namen und Versionen verschiedener Serversoftware angeben, um die Zustellung zu stoppen, z. B. aufgrund von Sicherheitslücken. Diese Versionsinformationen werden vom Server bereitgestellt und ihre Zuverlässigkeit ist nicht garantiert. Es wird jedoch empfohlen, eine Vorabversion anzugeben, wie z. B. >= 2024.3.1-0, da die Angabe >= 2024.3.1 keine benutzerdefinierten Versionen wie 2024.3.1-custom.0 einschließt."
_accountMigration:
moveFrom: "Von einem anderen Konto zu diesem migrieren"
moveFromSub: "Alias für ein anderes Konto erstellen"
+8 -3
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "Silence this instance"
mediaSilenceThisInstance: "Media-silence this server"
operations: "Operations"
software: "Software"
softwareName: "Software"
version: "Version"
metadata: "Metadata"
withNFiles: "{n} file(s)"
@@ -250,7 +251,6 @@ noUsers: "There are no users"
editProfile: "Edit profile"
noteDeleteConfirm: "Are you sure you want to delete this note?"
pinLimitExceeded: "You cannot pin any more notes"
intro: "Installation of Misskey has been finished! Please create an admin user."
done: "Done"
processing: "Processing..."
preview: "Preview"
@@ -784,7 +784,6 @@ thisIsExperimentalFeature: "This is an experimental feature. Its functionality i
developer: "Developer"
makeExplorable: "Make account visible in \"Explore\""
makeExplorableDescription: "If you turn this off, your account will not show up in the \"Explore\" section."
showGapBetweenNotesInTimeline: "Show a gap between posts on the timeline"
duplicate: "Duplicate"
left: "Left"
center: "Center"
@@ -1237,7 +1236,6 @@ showAvatarDecorations: "Show avatar decorations"
releaseToRefresh: "Release to refresh"
refreshing: "Refreshing..."
pullDownToRefresh: "Pull down to refresh"
disableStreamingTimeline: "Disable real-time timeline updates"
useGroupedNotifications: "Display grouped notifications"
signupPendingError: "There was a problem verifying the email address. The link may have expired."
cwNotationRequired: "If \"Hide content\" is enabled, a description must be provided."
@@ -1347,6 +1345,7 @@ readonly: "Read only"
goToDeck: "Return to Deck"
federationJobs: "Federation Jobs"
driveAboutTip: "In Drive, a list of files you've uploaded in the past will be displayed. <br> \nYou can reuse these files when attaching them to notes, or you can upload files in advance to post later. <br> \n<b>Be careful when deleting a file, as it will not be available in all places where it was used (such as notes, pages, avatars, banners, etc.).</b> <br> \nYou can also create folders to organize your files."
scrollToClose: "Scroll to close"
_chat:
noMessagesYet: "No messages yet"
newMessage: "New message"
@@ -1423,6 +1422,8 @@ _settings:
ifOn: "When turned on"
ifOff: "When turned off"
enableSyncThemesBetweenDevices: "Synchronize installed themes across devices"
enablePullToRefresh: "Pull to Refresh"
enablePullToRefresh_description: "When using a mouse, drag while pressing in the scroll wheel."
_chat:
showSenderName: "Show sender's name"
sendOnEnter: "Press Enter to send"
@@ -1430,6 +1431,7 @@ _preferencesProfile:
profileName: "Profile name"
profileNameDescription: "Set a name that identifies this device."
profileNameDescription2: "Example: \"Main PC\", \"Smartphone\""
manageProfiles: "Manage Profiles"
_preferencesBackup:
autoBackup: "Auto backup"
restoreFromBackup: "Restore from backup"
@@ -1468,6 +1470,7 @@ _delivery:
manuallySuspended: "Manually suspended"
goneSuspended: "Server is suspended due to server deletion"
autoSuspendedForNotResponding: "Server is suspended due to no responding"
softwareSuspended: "Suspended as this software is no longer being distributed to"
_bubbleGame:
howToPlay: "How to play"
hold: "Hold"
@@ -1599,6 +1602,8 @@ _serverSettings:
openRegistration: "Make the account creation open"
openRegistrationWarning: "Opening registration carries risks. It is recommended to only enable it if you have a system in place to continuously monitor the server and respond immediately in case of any issues."
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "If no moderator activity is detected for a while, this setting will be automatically turned off to prevent spam."
deliverSuspendedSoftware: "Suspended Software"
deliverSuspendedSoftwareDescription: "You can specify a range of names and versions of the server's software to stop delivery for vulnerability or other reasons. This version information is provided by the server and is not guaranteed to be reliable. A semver range specification can be used to specify the version, but specifying >= 2024.3.1 will not include custom versions such as 2024.3.1-custom.0, so it is recommended that a prerelease specification be used, such as >= 2024.3.1-0"
_accountMigration:
moveFrom: "Migrate another account to this one"
moveFromSub: "Create alias to another account"
-3
View File
@@ -250,7 +250,6 @@ noUsers: "No hay usuarios"
editProfile: "Editar perfil"
noteDeleteConfirm: "¿Desea borrar esta nota?"
pinLimitExceeded: "Ya no se pueden fijar más posts"
intro: "¡La instalación de Misskey ha terminado! Crea el usuario administrador."
done: "Terminado"
processing: "Procesando"
preview: "Vista previa"
@@ -784,7 +783,6 @@ thisIsExperimentalFeature: "Se trata de una función experimental. Las especific
developer: "Desarrolladores"
makeExplorable: "Hacer visible la cuenta en \"Explorar\""
makeExplorableDescription: "Si desactiva esta opción, su cuenta no aparecerá en la sección \"Explorar\"."
showGapBetweenNotesInTimeline: "Mostrar un intervalo entre notas en la línea de tiempo"
duplicate: "Duplicar"
left: "Izquierda"
center: "Centrar"
@@ -1237,7 +1235,6 @@ showAvatarDecorations: "Mostrar decoraciones de avatar"
releaseToRefresh: "Soltar para recargar"
refreshing: "Recargando..."
pullDownToRefresh: "Tira hacia abajo para recargar"
disableStreamingTimeline: "Desactivar actualizaciones en tiempo real de la línea de tiempo"
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."
cwNotationRequired: "Si se ha activado \"ocultar contenido\", es necesario proporcionar una descripción."
-3
View File
@@ -238,7 +238,6 @@ noUsers: "Il ny a pas dutilisateur·rice·s"
editProfile: "Modifier votre profil"
noteDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note ?"
pinLimitExceeded: "Vous ne pouvez plus épingler dautres notes."
intro: "Linstallation de Misskey est terminée ! Veuillez créer un compte administrateur."
done: "Terminé"
processing: "Traitement en cours"
preview: "Aperçu"
@@ -760,7 +759,6 @@ thisIsExperimentalFeature: "Ceci est une fonctionnalité expérimentale. Il y a
developer: "Développeur"
makeExplorable: "Rendre le compte visible sur la page \"Découvrir\"."
makeExplorableDescription: "Si vous désactivez cette option, votre compte n'apparaîtra pas sur la page \"Découvrir\"."
showGapBetweenNotesInTimeline: "Afficher un écart entre les notes sur la Timeline"
duplicate: "Duliquer"
left: "Gauche"
center: "Centrer"
@@ -1209,7 +1207,6 @@ showAvatarDecorations: "Afficher les décorations d'avatar"
releaseToRefresh: "Relâcher pour rafraîchir"
refreshing: "Rafraîchissement..."
pullDownToRefresh: "Tirer vers le bas pour rafraîchir"
disableStreamingTimeline: "Désactiver les mises à jour en temps réel de la ligne du temps"
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."
-3
View File
@@ -241,7 +241,6 @@ noUsers: "Tidak ada pengguna"
editProfile: "Sunting profil"
noteDeleteConfirm: "Apakah kamu yakin ingin menghapus catatan ini?"
pinLimitExceeded: "Kamu tidak dapat menyematkan catatan lagi"
intro: "Instalasi Misskey telah selesai! Mohon untuk membuat pengguna admin."
done: "Selesai"
processing: "Memproses"
preview: "Pratinjau"
@@ -761,7 +760,6 @@ thisIsExperimentalFeature: "Fitur ini eksperimental. Fungsionalitas dari fitur i
developer: "Pengembang"
makeExplorable: "Buat akun tampil di \"Jelajahi\""
makeExplorableDescription: "Jika kamu mematikan ini, akun kamu tidak akan muncul di menu \"Jelajahi\""
showGapBetweenNotesInTimeline: "Tampilkan jarak diantara catatan pada lini masa"
duplicate: "Duplikat"
left: "Kiri"
center: "Tengah"
@@ -1206,7 +1204,6 @@ showAvatarDecorations: "Tampilkan dekorasi avatar"
releaseToRefresh: "Lepaskan untuk memuat ulang"
refreshing: "Sedang memuat ulang..."
pullDownToRefresh: "Tarik ke bawah untuk memuat ulang"
disableStreamingTimeline: "Nonaktifkan pembaharuan lini masa real-time"
useGroupedNotifications: "Tampilkan notifikasi secara dikelompokkan"
signupPendingError: "Terdapat masalah ketika memverifikasi alamat surel. Tautan kemungkinan telah kedaluwarsa."
cwNotationRequired: "Jika \"Sembunyikan konten\" diaktifkan, deskripsi harus disediakan."
+262 -12
View File
@@ -898,6 +898,10 @@ export interface Locale extends ILocale {
*
*/
"software": string;
/**
*
*/
"softwareName": string;
/**
*
*/
@@ -1018,10 +1022,6 @@ export interface Locale extends ILocale {
*
*/
"pinLimitExceeded": string;
/**
* Misskeyのインストールが完了しました
*/
"intro": string;
/**
*
*/
@@ -2318,6 +2318,10 @@ export interface Locale extends ILocale {
*
*/
"newNoteRecived": string;
/**
*
*/
"newNote": string;
/**
*
*/
@@ -3154,10 +3158,6 @@ export interface Locale extends ILocale {
*
*/
"makeExplorableDescription": string;
/**
*
*/
"showGapBetweenNotesInTimeline": string;
/**
*
*/
@@ -4966,10 +4966,6 @@ export interface Locale extends ILocale {
*
*/
"pullDownToRefresh": string;
/**
*
*/
"disableStreamingTimeline": string;
/**
*
*/
@@ -5409,6 +5405,26 @@ export interface Locale extends ILocale {
*
*/
"driveAboutTip": string;
/**
*
*/
"scrollToClose": string;
/**
*
*/
"advice": string;
/**
*
*/
"realtimeMode": string;
/**
*
*/
"turnItOn": string;
/**
*
*/
"turnItOff": string;
"_chat": {
/**
*
@@ -5705,6 +5721,30 @@ export interface Locale extends ILocale {
*
*/
"enableSyncThemesBetweenDevices": string;
/**
*
*/
"enablePullToRefresh": string;
/**
*
*/
"enablePullToRefresh_description": string;
/**
*
*/
"realtimeMode_description": string;
/**
*
*/
"contentsUpdateFrequency": string;
/**
*
*/
"contentsUpdateFrequency_description": string;
/**
*
*/
"contentsUpdateFrequency_description2": string;
"_chat": {
/**
*
@@ -5729,6 +5769,10 @@ export interface Locale extends ILocale {
* : PC
*/
"profileNameDescription2": string;
/**
*
*/
"manageProfiles": string;
};
"_preferencesBackup": {
/**
@@ -5871,6 +5915,10 @@ export interface Locale extends ILocale {
*
*/
"autoSuspendedForNotResponding": string;
/**
*
*/
"softwareSuspended": string;
};
};
"_bubbleGame": {
@@ -6356,6 +6404,48 @@ export interface Locale extends ILocale {
*
*/
"thisSettingWillAutomaticallyOffWhenModeratorsInactive": string;
/**
*
*/
"deliverSuspendedSoftware": string;
/**
* semver 使>= 2024.3.1 2024.3.1-custom.0 >= 2024.3.1-0 prerelease
*/
"deliverSuspendedSoftwareDescription": string;
/**
*
*/
"singleUserMode": string;
/**
*
*/
"singleUserMode_description": string;
/**
*
*/
"userGeneratedContentsVisibilityForVisitor": string;
/**
*
*/
"userGeneratedContentsVisibilityForVisitor_description": string;
/**
*
*/
"userGeneratedContentsVisibilityForVisitor_description2": string;
"_userGeneratedContentsVisibilityForVisitor": {
/**
*
*/
"all": string;
/**
*
*/
"localOnly": string;
/**
*
*/
"none": string;
};
};
"_accountMigration": {
/**
@@ -11588,6 +11678,166 @@ export interface Locale extends ILocale {
*/
"serverHostPlaceholder": string;
};
"_serverSetupWizard": {
/**
* Misskeyのインストールが完了しました
*/
"installCompleted": string;
/**
*
*/
"firstCreateAccount": string;
/**
*
*/
"accountCreated": string;
/**
*
*/
"serverSetting": string;
/**
*
*/
"youCanEasilyConfigureOptimalServerSettingsWithThisWizard": string;
/**
*
*/
"settingsYouMakeHereCanBeChangedLater": string;
/**
* Misskeyをどのように使いますか
*/
"howWillYouUseMisskey": string;
"_use": {
/**
*
*/
"single": string;
/**
* 使
*/
"single_description": string;
/**
*
*/
"single_youCanCreateMultipleAccounts": string;
/**
*
*/
"group": string;
/**
* 使
*/
"group_description": string;
/**
*
*/
"open": string;
/**
*
*/
"open_description": string;
};
/**
*
*/
"openServerAdvice": string;
/**
* reCAPTCHAといったアンチボット機能を有効にするなど
*/
"openServerAntiSpamAdvice": string;
/**
*
*/
"howManyUsersDoYouExpect": string;
"_scale": {
/**
* 100 ()
*/
"small": string;
/**
* 1001000 ()
*/
"medium": string;
/**
* 1000 ()
*/
"large": string;
};
/**
*
*/
"largeScaleServerAdvice": string;
/**
* Fediverseと接続しますか
*/
"doYouConnectToFediverse": string;
/**
* (Fediverse)
*/
"doYouConnectToFediverse_description1": string;
/**
* Fediverseと接続することは
*/
"doYouConnectToFediverse_description2": string;
/**
*
*/
"youCanConfigureMoreFederationSettingsLater": string;
/**
*
*/
"adminInfo": string;
/**
* 使
*/
"adminInfo_description": string;
/**
*
*/
"adminInfo_mustBeFilled": string;
/**
*
*/
"followingSettingsAreRecommended": string;
/**
*
*/
"applyTheseSettings": string;
/**
*
*/
"skipSettings": string;
/**
*
*/
"settingsCompleted": string;
/**
* 使
*/
"settingsCompleted_description": string;
/**
*
*/
"settingsCompleted_description2": string;
/**
*
*/
"donationRequest": string;
"_donationRequest": {
/**
* Misskeyは有志によって開発されている無料のソフトウェアです
*/
"text1": string;
/**
*
*/
"text2": string;
/**
*
*/
"text3": string;
};
};
}
declare const locales: {
[lang: string]: Locale;
-3
View File
@@ -250,7 +250,6 @@ noUsers: "Non ci sono profili"
editProfile: "Modifica profilo"
noteDeleteConfirm: "Vuoi davvero eliminare questa Nota?"
pinLimitExceeded: "Non puoi fissare altre note "
intro: "L'installazione di Misskey è terminata! Si prega di creare il profilo amministratore."
done: "Fine"
processing: "In elaborazione"
preview: "Anteprima"
@@ -784,7 +783,6 @@ thisIsExperimentalFeature: "Questa è una funzionalità sperimentale. Potrebbe e
developer: "Sviluppatore"
makeExplorable: "Profilo visibile pubblicamente nella pagina \"Esplora\""
makeExplorableDescription: "Disabilitando questa opzione, il tuo profilo non verrà elencato nella pagina \"Esplora\"."
showGapBetweenNotesInTimeline: "Mostrare un intervallo tra le note sulla timeline"
duplicate: "Duplica"
left: "Sinistra"
center: "Centro"
@@ -1237,7 +1235,6 @@ showAvatarDecorations: "Mostra decorazione della foto profilo"
releaseToRefresh: "Rilascia per aggiornare"
refreshing: "Aggiornamento..."
pullDownToRefresh: "Trascinare per aggiornare"
disableStreamingTimeline: "Disabilitare gli aggiornamenti della TL in tempo reale"
useGroupedNotifications: "Mostra le notifiche raggruppate"
signupPendingError: "Si è verificato un problema durante la verifica del tuo indirizzo email. Potrebbe essere scaduto il collegamento temporaneo."
cwNotationRequired: "Devi indicare perché il contenuto è indicato come esplicito."
+70 -3
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "サーバーをサイレンス"
mediaSilenceThisInstance: "サーバーをメディアサイレンス"
operations: "操作"
software: "ソフトウェア"
softwareName: "ソフトウェア名"
version: "バージョン"
metadata: "メタデータ"
withNFiles: "{n}つのファイル"
@@ -250,7 +251,6 @@ noUsers: "ユーザーはいません"
editProfile: "プロフィールを編集"
noteDeleteConfirm: "このノートを削除しますか?"
pinLimitExceeded: "これ以上ピン留めできません"
intro: "Misskeyのインストールが完了しました!管理者アカウントを作成しましょう。"
done: "完了"
processing: "処理中"
preview: "プレビュー"
@@ -575,6 +575,7 @@ showFixedPostForm: "タイムライン上部に投稿フォームを表示する
showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)"
withRepliesByDefaultForNewlyFollowed: "フォローする際、デフォルトで返信をTLに含むようにする"
newNoteRecived: "新しいノートがあります"
newNote: "新しいノート"
sounds: "サウンド"
sound: "サウンド"
listen: "聴く"
@@ -784,7 +785,6 @@ thisIsExperimentalFeature: "これは実験的な機能です。仕様が変更
developer: "開発者"
makeExplorable: "アカウントを見つけやすくする"
makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らなくなります。"
showGapBetweenNotesInTimeline: "タイムラインのノートを離して表示"
duplicate: "複製"
left: "左"
center: "中央"
@@ -1237,7 +1237,6 @@ showAvatarDecorations: "アイコンのデコレーションを表示"
releaseToRefresh: "離してリロード"
refreshing: "リロード中"
pullDownToRefresh: "引っ張ってリロード"
disableStreamingTimeline: "タイムラインのリアルタイム更新を無効にする"
useGroupedNotifications: "通知をグルーピング"
signupPendingError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。"
cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要です。"
@@ -1347,6 +1346,11 @@ readonly: "読み取り専用"
goToDeck: "デッキへ戻る"
federationJobs: "連合ジョブ"
driveAboutTip: "ドライブでは、過去にアップロードしたファイルの一覧が表示されます。<br>\nノートに添付する際に再利用したり、あとで投稿するファイルを予めアップロードしておくこともできます。<br>\n<b>ファイルを削除すると、今までそのファイルを使用した全ての場所(ノート、ページ、アバター、バナー等)からも見えなくなるので注意してください。</b><br>\nフォルダを作って整理することもできます。"
scrollToClose: "スクロールして閉じる"
advice: "アドバイス"
realtimeMode: "リアルタイムモード"
turnItOn: "オンにする"
turnItOff: "オフにする"
_chat:
noMessagesYet: "まだメッセージはありません"
@@ -1426,6 +1430,12 @@ _settings:
ifOn: "オンのとき"
ifOff: "オフのとき"
enableSyncThemesBetweenDevices: "デバイス間でインストールしたテーマを同期"
enablePullToRefresh: "ひっぱって更新"
enablePullToRefresh_description: "マウスでは、ホイールを押し込みながらドラッグします。"
realtimeMode_description: "サーバーと接続を確立し、リアルタイムでコンテンツを更新します。通信量とバッテリーの消費が多くなる場合があります。"
contentsUpdateFrequency: "コンテンツの取得頻度"
contentsUpdateFrequency_description: "高いほどリアルタイムにコンテンツが更新されますが、パフォーマンスが低下し、通信量とバッテリーの消費が多くなります。"
contentsUpdateFrequency_description2: "リアルタイムモードがオンのときは、この設定に関わらずリアルタイムでコンテンツが更新されます。"
_chat:
showSenderName: "送信者の名前を表示"
@@ -1435,6 +1445,7 @@ _preferencesProfile:
profileName: "プロファイル名"
profileNameDescription: "このデバイスを識別する名前を設定してください。"
profileNameDescription2: "例: 「メインPC」、「スマホ」など"
manageProfiles: "プロファイルの管理"
_preferencesBackup:
autoBackup: "自動バックアップ"
@@ -1477,6 +1488,7 @@ _delivery:
manuallySuspended: "手動停止中"
goneSuspended: "サーバー削除のため停止中"
autoSuspendedForNotResponding: "サーバー応答なしのため停止中"
softwareSuspended: "配信停止中のソフトウェアであるため停止中"
_bubbleGame:
howToPlay: "遊び方"
@@ -1615,6 +1627,18 @@ _serverSettings:
openRegistration: "アカウントの作成をオープンにする"
openRegistrationWarning: "登録を開放することはリスクが伴います。サーバーを常に監視し、トラブルが発生した際にすぐに対応できる体制がある場合のみオンにすることを推奨します。"
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。"
deliverSuspendedSoftware: "配信停止中のソフトウェア"
deliverSuspendedSoftwareDescription: "脆弱性などの理由で、サーバーのソフトウェアの名前及びバージョンの範囲を指定して配信を停止できます。このバージョン情報はサーバーが提供したものであり、信頼性は保証されません。バージョン指定には semver の範囲指定が使用できますが、>= 2024.3.1 と指定すると 2024.3.1-custom.0 のようなカスタムバージョンが含まれないため、>= 2024.3.1-0 のように prerelease の指定を行うことを推奨します。"
singleUserMode: "お一人様モード"
singleUserMode_description: "このサーバーを利用するのが自分だけの場合、このモードを有効にすることで動作が最適化されます。"
userGeneratedContentsVisibilityForVisitor: "非利用者に対するユーザー作成コンテンツの公開範囲"
userGeneratedContentsVisibilityForVisitor_description: "モデレーションが行き届きにくい不適切なリモートコンテンツなどが、自サーバー経由で図らずもインターネットに公開されてしまうことによるトラブル防止などに役立ちます。"
userGeneratedContentsVisibilityForVisitor_description2: "サーバーで受信したリモートのコンテンツを含め、サーバー内の全てのコンテンツを無条件でインターネットに公開することはリスクが伴います。特に、分散型の特性を知らない閲覧者にとっては、リモートのコンテンツであってもサーバー内で作成されたコンテンツであると誤って認識してしまう可能性があるため、注意が必要です。"
_userGeneratedContentsVisibilityForVisitor:
all: "全て公開"
localOnly: "ローカルコンテンツのみ公開し、リモートコンテンツは非公開"
none: "全て非公開"
_accountMigration:
moveFrom: "別のアカウントからこのアカウントに移行"
@@ -3099,3 +3123,46 @@ _search:
pleaseEnterServerHost: "サーバーのホストを入力してください"
pleaseSelectUser: "ユーザーを選択してください"
serverHostPlaceholder: "例: misskey.example.com"
_serverSetupWizard:
installCompleted: "Misskeyのインストールが完了しました!"
firstCreateAccount: "まずは、管理者アカウントを作成しましょう。"
accountCreated: "管理者アカウントが作成されました!"
serverSetting: "サーバーの設定"
youCanEasilyConfigureOptimalServerSettingsWithThisWizard: "このウィザードで簡単に最適なサーバーの設定が行えます。"
settingsYouMakeHereCanBeChangedLater: "ここでの設定は、あとからでも変更できます。"
howWillYouUseMisskey: "Misskeyをどのように使いますか?"
_use:
single: "お一人様サーバー"
single_description: "自分専用のサーバーとして、一人で使う"
single_youCanCreateMultipleAccounts: "お一人様サーバーとして運用する場合でも、アカウントは必要に応じて複数作成可能です。"
group: "グループサーバー"
group_description: "信頼できる他の利用者を招待して、複数人で使う"
open: "オープンサーバー"
open_description: "不特定多数の利用者を受け入れる運営を行う"
openServerAdvice: "不特定多数の利用者を受け入れることはリスクが伴います。トラブルに対処できるよう、確実なモデレーション体制で運営することを推奨します。"
openServerAntiSpamAdvice: "自サーバーがスパムの踏み台にならないように、reCAPTCHAといったアンチボット機能を有効にするなど、セキュリティについても細心の注意が必要です。"
howManyUsersDoYouExpect: "どれくらいの人数を想定していますか?"
_scale:
small: "100人以下 (小規模)"
medium: "100人以上1000人以下 (中規模)"
large: "1000人以上 (大規模)"
largeScaleServerAdvice: "大規模なサーバーでは、ロードバランシングやデータベースのレプリケーションなど、高度なインフラストラクチャーの知識が必要になる場合があります。"
doYouConnectToFediverse: "Fediverseと接続しますか?"
doYouConnectToFediverse_description1: "分散型サーバーで構成されるネットワーク(Fediverse)に接続すると、他のサーバーと相互にコンテンツのやり取りが可能です。"
doYouConnectToFediverse_description2: "Fediverseと接続することは「連合」とも呼ばれます。"
youCanConfigureMoreFederationSettingsLater: "連合可能なサーバーの指定など、高度な設定も後ほど可能です。"
adminInfo: "管理者情報"
adminInfo_description: "問い合わせを受け付けるために使用される管理者情報を設定します。"
adminInfo_mustBeFilled: "オープンサーバー、または連合がオンの場合は必ず入力が必要です。"
followingSettingsAreRecommended: "以下の設定が推奨されます"
applyTheseSettings: "この設定を適用"
skipSettings: "設定をスキップ"
settingsCompleted: "設定が完了しました!"
settingsCompleted_description: "お疲れ様でした。準備が整ったので、さっそくサーバーの使用を開始できます。"
settingsCompleted_description2: "詳細なサーバー設定は、「コントロールパネル」から行えます。"
donationRequest: "寄付のお願い"
_donationRequest:
text1: "Misskeyは有志によって開発されている無料のソフトウェアです。"
text2: "今後も開発を続けられるように、よろしければぜひカンパをお願いいたします。"
text3: "支援者向け特典もあります!"
-3
View File
@@ -250,7 +250,6 @@ noUsers: "ユーザーはおらん"
editProfile: "プロフィールをいじる"
noteDeleteConfirm: "このノートをほかしてええか?"
pinLimitExceeded: "これ以上ピン留めできひん"
intro: "Misskeyのインストールが完了したで!管理者アカウントを作ってや。"
done: "でけた"
processing: "処理しとる"
preview: "プレビュー"
@@ -781,7 +780,6 @@ thisIsExperimentalFeature: "これは実験的な機能やから、仕様が変
developer: "開発者やで"
makeExplorable: "アカウントを見つけやすくするで"
makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らんくなるで。"
showGapBetweenNotesInTimeline: "タイムラインのノートを離して表示するで"
duplicate: "複製"
left: "左"
center: "真ん中"
@@ -1233,7 +1231,6 @@ showAvatarDecorations: "アイコンのデコレーション映す"
releaseToRefresh: "離したらリロード"
refreshing: "リロードしとる"
pullDownToRefresh: "引っ張ってリロードするで"
disableStreamingTimeline: "タイムラインのリアルタイム更新をやめるで"
useGroupedNotifications: "通知をグループ分けして出すで"
signupPendingError: "メアド確認してたらなんか変なことなったわ。リンクの期限切れてるかもしれん。"
cwNotationRequired: "「内容を隠す」んやったら注釈書かなアカンで。"
-1
View File
@@ -224,7 +224,6 @@ noUsers: "사용자가 어ᇝ십니다"
editProfile: "프로필 적기"
noteDeleteConfirm: "요 노트럴 뭉캡니꺼?"
pinLimitExceeded: "더 몬 붙입니다"
intro: "Misskey럴 다 깔앗십니다! 간리자 게정얼 맨걸어 보입시다."
done: "햇어예"
processing: "처리하고 잇어예"
preview: "미리보기"
+10 -3
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "서버를 사일런스"
mediaSilenceThisInstance: "서버의 미디어를 사일런스"
operations: "작업"
software: "소프트웨어"
softwareName: "소프트웨어 이름"
version: "버전"
metadata: "메타데이터"
withNFiles: "{n}개의 파일"
@@ -250,7 +251,6 @@ noUsers: "아무도 없습니다"
editProfile: "프로필 수정"
noteDeleteConfirm: "이 노트를 삭제하시겠습니까?"
pinLimitExceeded: "더 이상 고정할 수 없습니다."
intro: "Misskey의 설치가 완료되었습니다! 관리자 계정을 생성해주세요."
done: "완료"
processing: "처리중"
preview: "미리보기"
@@ -784,7 +784,6 @@ thisIsExperimentalFeature: "이 기능은 실험적인 기능입니다. 사양
developer: "개발자"
makeExplorable: "계정을 쉽게 발견하도록 하기"
makeExplorableDescription: "비활성화하면 \"발견하기\"에 나의 계정을 표시하지 않습니다."
showGapBetweenNotesInTimeline: "타임라인의 노트 사이를 띄워서 표시"
duplicate: "복제"
left: "왼쪽"
center: "가운데"
@@ -1237,7 +1236,6 @@ showAvatarDecorations: "아바타 장식 표시"
releaseToRefresh: "놓아서 새로고침"
refreshing: "새로고침 중"
pullDownToRefresh: "아래로 내려서 새로고침"
disableStreamingTimeline: "타임라인의 실시간 갱신을 무효화하기"
useGroupedNotifications: "알림을 그룹화하고 표시"
signupPendingError: "메일 주소 확인중에 문제가 발생했습니다. 링크의 유효기간이 지났을 가능성이 있습니다."
cwNotationRequired: "'내용을 숨기기'를 체크한 경우 주석을 써야 합니다."
@@ -1346,6 +1344,8 @@ settingsMigrating: "설정을 이전하는 중입니다. 잠시 기다려주십
readonly: "읽기 전용"
goToDeck: "덱으로 돌아가기"
federationJobs: "연합 작업"
driveAboutTip: "드라이브는 이전에 업로드한 파일 목록을 표시해요. <br>\n노트에 첨부할 때 다시 사용하거나 나중에 게시할 파일을 미리 업로드할 수 있어요. <br>\n<b>파일을 삭제하면, 지금까지 그 파일을 사용한 모든 장소(노트, 페이지, 아바타, 배너 등)에서도 보이지 않게 되므로 주의해 주세요. 폴더를 만들고 정리할 수도 있어요.</b><br>"
scrollToClose: "스크롤하여 닫기"
_chat:
noMessagesYet: "아직 메시지가 없습니다"
newMessage: "새로운 메시지"
@@ -1422,6 +1422,8 @@ _settings:
ifOn: "켜져 있을 때"
ifOff: "꺼져 있을 때"
enableSyncThemesBetweenDevices: "기기 간 설치한 테마 동기화"
enablePullToRefresh: "계속해서 갱신"
enablePullToRefresh_description: "마우스에서 휠을 누르면서 드래그해요."
_chat:
showSenderName: "발신자 이름 표시"
sendOnEnter: "엔터로 보내기"
@@ -1429,6 +1431,7 @@ _preferencesProfile:
profileName: "프로필 이름"
profileNameDescription: "이 디바이스를 식별할 이름을 설정해 주세요."
profileNameDescription2: "예: '메인PC', '스마트폰' 등"
manageProfiles: "프로파일 관리"
_preferencesBackup:
autoBackup: "자동 백업"
restoreFromBackup: "백업으로 복구"
@@ -1467,6 +1470,7 @@ _delivery:
manuallySuspended: "수동 정지 중"
goneSuspended: "서버 삭제를 이유로 정지 중"
autoSuspendedForNotResponding: "서버 응답 없음을 이유로 정지 중"
softwareSuspended: "전달 정지 중인 소프트웨어이므로 정지 중"
_bubbleGame:
howToPlay: "설명"
hold: "홀드"
@@ -1598,6 +1602,8 @@ _serverSettings:
openRegistration: "회원 가입을 활성화 하기"
openRegistrationWarning: "회원 가입을 개방하는 것은 리스크가 따릅니다. 서버를 항상 감시할 수 있고, 문제가 발생했을 때 바로 대응할 수 있는 상태에서만 활성화 하는 것을 권장합니다."
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "일정 기간동안 모더레이터의 활동이 감지되지 않는 경우, 스팸 방지를 위해 이 설정은 자동으로 꺼집니다."
deliverSuspendedSoftware: "전달 정지 중인 소프트웨어"
deliverSuspendedSoftwareDescription: "취약성 등의 이유로 서버의 소프트웨어 이름 및 버전 범위를 지정하여 전달을 정지할 수 있어요. 이 버전 정보는 서버가 제공한 것이며 신뢰성은 보장되지 않아요. 버전 지정에는 semver의 범위 지정을 사용할 수 있지만, >= 2024.3.1로 지정하면 2024.3.1-custom.0과 같은 custom.0과 같은 custom 버전이 포함되지 않기 때문에 >= 2024.3.1-0과 같이 prerelease를 지정하는 것이 좋아요."
_accountMigration:
moveFrom: "다른 계정에서 이 계정으로 이사"
moveFromSub: "다른 계정에 대한 별칭을 생성"
@@ -1915,6 +1921,7 @@ _role:
canManageCustomEmojis: "커스텀 이모지 관리"
canManageAvatarDecorations: "아바타 꾸미기 관리"
driveCapacity: "드라이브 용량"
maxFileSize: "업로드 가능한 최대 파일 크기"
alwaysMarkNsfw: "파일을 항상 NSFW로 지정"
canUpdateBioMedia: "아바타 및 배너 이미지 변경 허용"
pinMax: "고정할 수 있는 노트 수"
-2
View File
@@ -250,7 +250,6 @@ noUsers: "Er zijn geen gebruikers."
editProfile: "Bewerk Profiel"
noteDeleteConfirm: "Ben je zeker dat je dit bericht wil verwijderen?"
pinLimitExceeded: "Je kunt geen berichten meer vastprikken"
intro: "Installatie van Misskey geëindigd! Maak nu een beheerder aan."
done: "Klaar"
processing: "Bezig met verwerken"
preview: "Voorbeeld"
@@ -784,7 +783,6 @@ thisIsExperimentalFeature: "Dit is een experimentele functie. De functionaliteit
developer: "Ontwikkelaar"
makeExplorable: "Gebruikersaccount zichtbaar maken in “Verkennen”"
makeExplorableDescription: "Als deze optie is uitgeschakeld, is uw gebruikersaccount niet zichtbaar in het gedeelte “Verkennen”."
showGapBetweenNotesInTimeline: "Een gat tussen noten op de tijdlijn weergeven"
duplicate: "Dupliceren"
left: "Links"
center: "Center"
-1
View File
@@ -171,7 +171,6 @@ noUsers: "Det er ingen brukere"
editProfile: "Rediger profil"
noteDeleteConfirm: "Er du sikker på at du vil slette denne Noten?"
pinLimitExceeded: "Du kan ikke feste flere."
intro: "Installasjonen av Misskey er ferdig! Vennligst opprett en administratorkonto."
done: "Ferdig"
default: "Standard"
defaultValueIs: "Standard: {value}"
-2
View File
@@ -230,7 +230,6 @@ noUsers: "Brak użytkowników"
editProfile: "Edytuj profil"
noteDeleteConfirm: "Czy na pewno chcesz usunąć ten wpis?"
pinLimitExceeded: "Nie możesz przypiąć więcej wpisów."
intro: "Zakończono instalację Misskey! Utwórz konto administratora."
done: "Gotowe"
processing: "Przetwarzanie"
preview: "Podgląd"
@@ -749,7 +748,6 @@ thisIsExperimentalFeature: "Ta funkcja jest eksperymentalna. Jej funkcjonalnoś
developer: "Programista"
makeExplorable: "Pokazuj konto na stronie „Eksploruj”"
makeExplorableDescription: "Jeżeli wyłączysz tę opcję, Twoje konto nie będzie wyświetlać się w sekcji „Eksploruj”."
showGapBetweenNotesInTimeline: "Pokazuj odstęp między wpisami na osi czasu."
duplicate: "Duplikuj"
left: "Lewo"
center: "Wyśsrodkuj"
-3
View File
@@ -250,7 +250,6 @@ noUsers: "Sem usuários"
editProfile: "Editar Perfil"
noteDeleteConfirm: "Deseja excluir esta nota?"
pinLimitExceeded: "Não é possível fixar novas notas"
intro: "A instalação do Misskey está completa! Crie uma conta de administrador."
done: "Concluído"
processing: "Em Progresso"
preview: "Pré-visualizar"
@@ -784,7 +783,6 @@ thisIsExperimentalFeature: "Este é um recurso experimental. As funções podem
developer: "Programador"
makeExplorable: "Deixe a sua conta encontrável em \"Explorar\"."
makeExplorableDescription: "Se você desativá-lo, outros usuários não poderão encontrar a sua conta na aba Descoberta."
showGapBetweenNotesInTimeline: "Mostrar um espaço entre as notas na linha de tempo"
duplicate: "Duplicar"
left: "Esquerda"
center: "Centralizar"
@@ -1237,7 +1235,6 @@ showAvatarDecorations: "Exibir decorações de avatar"
releaseToRefresh: "Solte para atualizar"
refreshing: "Atualizando..."
pullDownToRefresh: "Puxe para baixo para atualizar"
disableStreamingTimeline: "Desabilitar atualizações em tempo real da linha do tempo"
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."
-2
View File
@@ -250,7 +250,6 @@ noUsers: "Niciun utilizator"
editProfile: "Editează profilul"
noteDeleteConfirm: "Ești sigur(ă) că vrei să ștergi această notă?"
pinLimitExceeded: "Nu poți mai fixa mai multe note"
intro: "Misskey s-a instalat! Te rog crează un utilizator admin."
done: "Gata"
processing: "Se procesează"
preview: "Previzualizare"
@@ -784,7 +783,6 @@ thisIsExperimentalFeature: "Aceasta este o funcție experimentală. Funcționali
developer: "Dezvoltator"
makeExplorable: "Fă-ți contul vizibil în secțiunea„Explorați”"
makeExplorableDescription: "Dacă dezactivezi această opțiune, contul dvs. nu va fi vizibil în secțiunea\"Explorați\"."
showGapBetweenNotesInTimeline: "Afișați un decalaj între postările de pe cronologie"
duplicate: "Duplicat"
left: "Stânga"
center: "Centru"
+41 -3
View File
@@ -5,6 +5,7 @@ introMisskey: "Добро пожаловать! Misskey — это децент
poweredByMisskeyDescription: "{name} – сервис на платформе с открытым исходным кодом <b>Misskey</b>, называемый экземпляром Misskey."
monthAndDay: "{day}.{month}"
search: "Поиск"
reset: "Сброс"
notifications: "Уведомления"
username: "Имя пользователя"
password: "Пароль"
@@ -48,6 +49,7 @@ pin: "Закрепить в профиле"
unpin: "Открепить от профиля"
copyContent: "Скопировать содержимое"
copyLink: "Скопировать ссылку"
copyRemoteLink: "Скопировать ссылку на репост"
copyLinkRenote: "Скопировать ссылку на репост"
delete: "Удалить"
deleteAndEdit: "Удалить и отредактировать"
@@ -215,8 +217,10 @@ perDay: "По дням"
stopActivityDelivery: "Остановить отправку обновлений активности"
blockThisInstance: "Блокировать этот инстанс"
silenceThisInstance: "Заглушить этот инстанс"
mediaSilenceThisInstance: "Заглушить сервер"
operations: "Операции"
software: "Программы"
softwareName: "Software Name"
version: "Версия"
metadata: "Метаданные"
withNFiles: "Файлы, {n} шт."
@@ -235,7 +239,11 @@ clearCachedFilesConfirm: "Удалить все закэшированные ф
blockedInstances: "Заблокированные инстансы"
blockedInstancesDescription: "Введите список инстансов, которые хотите заблокировать. Они больше не смогут обмениваться с вашим инстансом."
silencedInstances: "Заглушённые инстансы"
silencedInstancesDescription: "Перечислите имена серверов, которые вы хотите отключить, разделив их новой строкой. Все учетные записи, принадлежащие к указанным в списке серверам, будут заблокированы и смогут отправлять запросы только на повторное использование и не смогут указывать локальные учетные записи, если они не будут отслеживаться. Это не повлияет на заблокированные серверы."
mediaSilencedInstances: "Заглушённые сервера"
mediaSilencedInstancesDescription: "Укажите названия серверов, для которых вы хотите отключить доступ к файлам, по одному серверу в строке. Все учетные записи, принадлежащие к перечисленным серверам, будут считаться конфиденциальными и не смогут использовать пользовательские эмодзи. Это никак не повлияет на заблокированные серверы."
federationAllowedHosts: "Серверы, поддерживающие федерацию"
federationAllowedHostsDescription: "Укажите имена серверов, для которых вы хотите разрешить объединение, разделив их разделителями строк."
muteAndBlock: "Скрытие и блокировка"
mutedUsers: "Скрытые пользователи"
blockedUsers: "Заблокированные пользователи"
@@ -243,7 +251,6 @@ noUsers: "Нет ни одного пользователя"
editProfile: "Редактировать профиль"
noteDeleteConfirm: "Вы хотите удалить эту заметку?"
pinLimitExceeded: "Нельзя закрепить ещё больше заметок"
intro: "Установка Misskey завершена! А теперь создайте учетную запись администратора."
done: "Готово"
processing: "Обработка"
preview: "Предпросмотр"
@@ -294,6 +301,7 @@ uploadFromUrlMayTakeTime: "Загрузка может занять некото
explore: "Обзор"
messageRead: "Прочитали"
noMoreHistory: "История закончилась"
startChat: "Начать чат"
nUsersRead: "Прочитали {n}"
agreeTo: "Я соглашаюсь с {0}"
agree: "Согласен"
@@ -416,6 +424,7 @@ antennaExcludeBots: "Исключать ботов"
antennaKeywordsDescription: "Пишите слова через пробел в одной строке, чтобы ловить их появление вместе; на отдельных строках располагайте слова, или группы слов, чтобы ловить любые из них."
notifyAntenna: "Уведомлять о новых заметках"
withFileAntenna: "Только заметки с вложениями"
excludeNotesInSensitiveChannel: "Исключить заметки из конфиденциальных каналов"
enableServiceworker: "Включить ServiceWorker"
antennaUsersDescription: "Пишите каждое название аккаута на отдельной строке"
caseSensitive: "С учётом регистра"
@@ -446,6 +455,8 @@ totpDescription: "Описание приложения-аутентификат
moderator: "Модератор"
moderation: "Модерация"
moderationNote: "Примечания модератора"
moderationNoteDescription: "Вы можете заполнять заметки, которые будут доступны только модераторам."
addModerationNote: ""
moderationLogs: "Журнал модерации"
nUsersMentioned: "Упомянуло пользователей: {n}"
securityKeyAndPasskey: "Ключ безопасности и парольная фраза"
@@ -506,6 +517,8 @@ emojiStyle: "Стиль эмодзи"
native: "Системные"
menuStyle: "Стиль меню"
style: "Стиль"
drawer: "Панель"
popup: "Всплывающие окна"
showNoteActionsOnlyHover: "Показывать кнопки у заметок только при наведении"
showReactionsCount: "Видеть количество реакций на заметках"
noHistory: "История пока пуста"
@@ -560,6 +573,7 @@ serverLogs: "Журнал сервера"
deleteAll: "Удалить всё"
showFixedPostForm: "Показывать поле для ввода новой заметки наверху ленты"
showFixedPostFormInChannel: "Показывать поле для ввода новой заметки наверху ленты (каналы)"
withRepliesByDefaultForNewlyFollowed: "По умолчанию включайте ответы новых пользователей, на которых вы подписались, во временную шкалу"
newNoteRecived: "Появилась новая заметка"
sounds: "Звуки"
sound: "Звуки"
@@ -572,6 +586,7 @@ masterVolume: "Основная регулировка громкости"
notUseSound: "Выключить звук"
useSoundOnlyWhenActive: "Воспроизводить звук только когда Misskey активен."
details: "Подробнее"
renoteDetails: "Узнать больше"
chooseEmoji: "Выберите эмодзи"
unableToProcess: "Не удаётся завершить операцию"
recentUsed: "Последние использованные"
@@ -587,6 +602,8 @@ ascendingOrder: "по возрастанию"
descendingOrder: "По убыванию"
scratchpad: "Когтеточка"
scratchpadDescription: "«Когтеточка» — это место для опытов с AiScript. Здесь можно писать программы, взаимодействующие с Misskey, запускать и смотреть что из этого получается."
uiInspector: "Средство проверки пользовательского интерфейса"
uiInspectorDescription: "Вы можете просмотреть список экземпляров компонентов пользовательского интерфейса, существующих в памяти. Элементы пользовательского интерфейса генерируются с помощью серии функций Ui:C:."
output: "Выходы"
script: "Скрипт"
disablePagesScript: "Отключить скрипты на «Страницах»"
@@ -667,14 +684,19 @@ smtpSecure: "Использовать SSL/TLS для SMTP-соединений"
smtpSecureInfo: "Выключите при использовании STARTTLS."
testEmail: "Проверка доставки электронной почты"
wordMute: "Скрытие слов"
wordMuteDescription: "Сведите к минимуму записи, содержащие указанное утверждение. Нажмите на свернутую запись, чтобы отобразить ее."
hardWordMute: "Строгое скрытие слов"
showMutedWord: "Отображать слово без уведомления (звука)"
hardWordMuteDescription: "Скрыть заметки, содержащие указанное слово или фразу. В отличие от word mute, заметка будет полностью скрыта от просмотра."
regexpError: "Ошибка в регулярном выражении"
regexpErrorDescription: "В списке {tab} скрытых слов, в строке {line} обнаружена синтаксическая ошибка:"
instanceMute: "Глушение инстансов"
userSaysSomething: "{name} что-то сообщает"
userSaysSomethingAbout: "{name} что-то говорил о「{word}」"
makeActive: "Активировать"
display: "Отображение"
copy: "Копировать"
copiedToClipboard: "Скопированы в буфер обмена"
metrics: "Метрики"
overview: "Обзор"
logs: "Журналы"
@@ -762,7 +784,6 @@ thisIsExperimentalFeature: "Это экспериментальная функц
developer: "Разработчик"
makeExplorable: "Опубликовать профиль в «Обзоре»."
makeExplorableDescription: "Если выключить, ваш профиль не будет показан в разделе «Обзор»."
showGapBetweenNotesInTimeline: "Показывать разделитель между заметками в ленте"
duplicate: "Дубликат"
left: "Слева"
center: "По центру"
@@ -840,6 +861,7 @@ administration: "Управление"
accounts: "Учётные записи"
switch: "Переключение"
noMaintainerInformationWarning: "Не заполнены сведения об администраторах"
noInquiryUrlWarning: "URL-адрес контактной формы еще не задан."
noBotProtectionWarning: "Ботозащита не настроена"
configure: "Настроить"
postToGallery: "Опубликовать в галерею"
@@ -904,6 +926,7 @@ followersVisibility: "Видимость подписчиков"
continueThread: "Показать следующие ответы"
deleteAccountConfirm: "Учётная запись будет безвозвратно удалена. Подтверждаете?"
incorrectPassword: "Пароль неверен."
incorrectTotp: "Введен неверный одноразовый пароль или срок его действия истек."
voteConfirm: "Отдать голос за «{choice}»?"
hide: "Спрятать"
useDrawerReactionPickerForMobile: "Выдвижная палитра на мобильном устройстве"
@@ -928,6 +951,9 @@ oneHour: "1 час"
oneDay: "1 день"
oneWeek: "1 неделя"
oneMonth: "1 месяц"
threeMonths: "3 месяца"
oneYear: "1 год"
threeDays: "3 дня"
reflectMayTakeTime: "Изменения могут занять время для отображения"
failedToFetchAccountInformation: "Не удалось получить информацию об аккаунте"
rateLimitExceeded: "Ограничение скорости превышено"
@@ -952,6 +978,7 @@ document: "Документ"
numberOfPageCache: "Количество сохранённых страниц в кэше"
numberOfPageCacheDescription: "Описание количества страниц в кэше"
logoutConfirm: "Вы хотите выйти из аккаунта?"
logoutWillClearClientData: "Когда вы выйдете из системы, информация о конфигурации клиента будет удалена из браузера.Чтобы иметь возможность восстановить информацию о вашей конфигурации при повторном входе в систему, пожалуйста, включите опцию автоматического резервного копирования в настройках."
lastActiveDate: "Последняя дата использования"
statusbar: "Статусбар"
pleaseSelect: "Пожалуйста, выберите"
@@ -1001,6 +1028,7 @@ neverShow: "Больше не показывать"
remindMeLater: "Напомнить позже"
didYouLikeMisskey: "Вам нравится Misskey?"
pleaseDonate: "Сайт {host} работает на Misskey. Это бесплатное программное обеспечение, и ваши пожертвования очень бы помогли продолжать его разработку!"
correspondingSourceIsAvailable: "Соответствующий исходный код можно найти по адресу {anchor} "
roles: "Роли"
role: "Роль"
noRole: "Нет роли"
@@ -1056,6 +1084,7 @@ prohibitedWords: "Запрещённые слова"
prohibitedWordsDescription: "Включает вывод ошибки при попытке опубликовать пост, содержащий указанное слово/набор слов.\nМножество слов может быть указано, разделяемые новой строкой."
prohibitedWordsDescription2: "Разделение пробелом создаёт спецификацию AND, а разделение косой чертой создаёт регулярное выражение."
hiddenTags: "Скрытые хештеги"
hiddenTagsDescription: "Установленные теги не будут отображаться в тренде, можно установить несколько тегов."
notesSearchNotAvailable: "Поиск заметок недоступен"
license: "Лицензия"
unfavoriteConfirm: "Удалить избранное?"
@@ -1066,6 +1095,7 @@ retryAllQueuesConfirmTitle: "Хотите попробовать ещё раз?"
retryAllQueuesConfirmText: "Нагрузка на сервер может увеличиться"
enableChartsForRemoteUser: "Создание диаграмм для удалённых пользователей"
enableChartsForFederatedInstances: "Создание диаграмм для удалённых серверов"
enableStatsForFederatedInstances: "Получить информацию об удаленном сервере"
showClipButtonInNoteFooter: "Показать кнопку добавления в подборку в меню действий с заметкой"
reactionsDisplaySize: "Размер реакций"
limitWidthOfReaction: "Ограничить максимальную ширину реакций и отображать их в уменьшенном размере."
@@ -1101,6 +1131,7 @@ preservedUsernames: "Зарезервированные имена пользо
preservedUsernamesDescription: "Перечислите зарезервированные имена пользователей, отделяя их строками. Они станут недоступны при создании учётной записи. Это ограничение не применяется при создании учётной записи администраторами. Также, уже существующие учётные записи останутся без изменений."
createNoteFromTheFile: "Создать заметку из этого файла"
archive: "Архив"
archived: "Архивировано"
unarchive: "Разархивировать"
channelArchiveConfirmTitle: "Переместить {name} в архив?"
channelArchiveConfirmDescription: "Архивированные каналы перестанут отображаться в списке каналов или результатах поиска. В них также нельзя будет добавлять новые записи."
@@ -1121,6 +1152,7 @@ rolesThatCanBeUsedThisEmojiAsReaction: "Роли тех, кому можно и
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Если здесь ничего не указать, в качестве реакции эту эмодзи сможет использовать каждый."
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Эти роли должны быть общедоступными."
cancelReactionConfirm: "Вы действительно хотите удалить свою реакцию?"
changeReactionConfirm: "Вы действительно хотите удалить свою реакцию?"
later: "Позже"
goToMisskey: "К Misskey"
additionalEmojiDictionary: "Дополнительные словари эмодзи"
@@ -1130,9 +1162,16 @@ enableServerMachineStats: "Опубликовать характеристики
enableIdenticonGeneration: "Включить генерацию иконки пользователя"
turnOffToImprovePerformance: "Отключение этого параметра может повысить производительность."
createInviteCode: "Создать код приглашения"
createWithOptions: "Используйте параметры для создания"
createCount: "Количество приглашений"
inviteCodeCreated: "Создан пригласительный код"
inviteLimitExceeded: "Достигнут предел количества пригласительных кодов, которые могут быть созданы."
createLimitRemaining: "Пригласительные коды, которые могут быть созданы: {limit} "
inviteLimitResetCycle: "За определенное {time} Вы можете создать неограниченное количество пригласительных кодов {limit} "
expirationDate: "Дата истечения"
noExpirationDate: "Бессрочно"
inviteCodeUsedAt: "Дата и время, когда был использован пригласительный код"
registeredUserUsingInviteCode: "Пользователи, которые использовали пригласительный код"
unused: "Неиспользованное"
used: "Использован"
expired: "Срок действия приглашения истёк"
@@ -1159,7 +1198,6 @@ privacyPolicyUrl: "Ссылка на Политику Конфиденциаль
attach: "Прикрепить"
angle: "Угол"
flip: "Переворот"
disableStreamingTimeline: "Отключить обновление ленты в режиме реального времени"
useGroupedNotifications: "Отображать уведомления сгруппировано"
doReaction: "Добавить реакцию"
code: "Код"
-2
View File
@@ -204,7 +204,6 @@ noUsers: "Žiadni používatelia"
editProfile: "Upraviť profil"
noteDeleteConfirm: "Naozaj chcete odstrániť túto poznámku?"
pinLimitExceeded: "Ďalšie poznámky už nemôžete pripnúť."
intro: "Inštalácia Misskey je dokončená! Prosím vytvorte administrátora."
done: "Hotovo"
processing: "Pracujem..."
preview: "Náhľad"
@@ -682,7 +681,6 @@ experimentalFeatures: "Experimentálne funkcie"
developer: "Vývojár"
makeExplorable: "Spraviť účet viditeľný v \"Objavovať\""
makeExplorableDescription: "Ak toto vypnete, váš účet sa nezobrazí v sekcii \"Objavovat\"."
showGapBetweenNotesInTimeline: "Zobraziť medzeru medzi príspevkami časovej osi."
duplicate: "Duplikovať"
left: "Naľavo"
center: "Stred"
-1
View File
@@ -211,7 +211,6 @@ noUsers: "Det finns inga användare"
editProfile: "Redigera profil"
noteDeleteConfirm: "Är du säker på att du vill ta bort denna not?"
pinLimitExceeded: "Du kan inte fästa fler noter"
intro: "Misskey har installerats! Vänligen skapa en adminanvändare."
done: "Klar"
processing: "Bearbetar..."
preview: "Förhandsvisning"
-3
View File
@@ -250,7 +250,6 @@ noUsers: "ไม่พบผู้ใช้งาน"
editProfile: "แก้ไขโปรไฟล์"
noteDeleteConfirm: "ต้องการลบโน้ตนี้ใช่ไหม?"
pinLimitExceeded: "คุณไม่สามารถปักหมุดโน้ตเพิ่มเติมใดๆได้อีก"
intro: "การติดตั้ง Misskey เสร็จสิ้นแล้วนะ! โปรดสร้างผู้ใช้งานที่เป็นผู้ดูแลระบบ"
done: "เสร็จสิ้น"
processing: "กำลังประมวลผล..."
preview: "แสดงตัวอย่าง"
@@ -778,7 +777,6 @@ thisIsExperimentalFeature: "นี่เป็นฟีเจอร์ทดล
developer: "สำหรับนักพัฒนา"
makeExplorable: "ทำให้บัญชีมองเห็นใน “สำรวจ”"
makeExplorableDescription: "ถ้าหากคุณปิดการทำงานนี้ บัญชีของคุณนั้นจะไม่แสดงในส่วน “สำรวจ”"
showGapBetweenNotesInTimeline: "แสดงช่องว่างระหว่างโพสต์บนไทม์ไลน์"
duplicate: "ทำซ้ำ"
left: "ซ้าย"
center: "กึ่งกลาง"
@@ -1227,7 +1225,6 @@ showAvatarDecorations: "แสดงตกแต่งอวตาร"
releaseToRefresh: "ปล่อยเพื่อรีเฟรช"
refreshing: "กำลังรีเฟรช..."
pullDownToRefresh: "ดึงลงเพื่อรีเฟรช"
disableStreamingTimeline: "ปิดใช้งานอัปเดตไทม์ไลน์แบบเรียลไทม์"
useGroupedNotifications: "แสดงผลการแจ้งเตือนแบบกลุ่มแล้ว"
signupPendingError: "มีปัญหาในการตรวจสอบที่อยู่อีเมลลิงก์อาจหมดอายุแล้ว"
cwNotationRequired: "หากเปิดใช้งาน “ซ่อนเนื้อหา” จะต้องระบุคำอธิบาย"
-1
View File
@@ -224,7 +224,6 @@ noUsers: "Kullanıcı yok"
editProfile: "Profili düzenle"
noteDeleteConfirm: "Bu notu silmek istediğinizden emin misiniz?"
pinLimitExceeded: "Daha fazla not sabitlenemez"
intro: "Misskey yüklemesi tamamlandı! Lütfen yönetici hesabını oluşturun."
done: "Tamamlandı"
preview: "Önizleme"
default: "Varsayılan"
-2
View File
@@ -208,7 +208,6 @@ noUsers: "Немає користувачів"
editProfile: "Редагувати обліковий запис"
noteDeleteConfirm: "Ви дійсно хочете видалити цей запис?"
pinLimitExceeded: "Більше записів не можна закріпити"
intro: "Встановлення Misskey завершено! Будь ласка, створіть обліковий запис адміністратора."
done: "Готово"
processing: "Обробка"
preview: "Попередній перегляд"
@@ -681,7 +680,6 @@ experimentalFeatures: "Експериментальні функції"
developer: "Розробник"
makeExplorable: "Зробіть обліковий запис видимим у розділі \"Огляд\""
makeExplorableDescription: "Вимкніть, щоб обліковий запис не показувався у розділі \"Огляд\"."
showGapBetweenNotesInTimeline: "Показувати розрив між записами у стрічці новин"
duplicate: "Дублікат"
left: "Лівий"
center: "Центр"
-1
View File
@@ -219,7 +219,6 @@ noUsers: "Foydalanuvchilar yoq"
editProfile: "Profilni o'zgartirish"
noteDeleteConfirm: "Haqiqatan ham bu qaydni oʻchirib tashlamoqchimisiz?"
pinLimitExceeded: "Siz boshqa qaydlarni mahkamlay olmaysiz"
intro: "Misskeyni o'rnatish tugallandi! Iltimos, administrator foydalanuvchi yarating."
done: "Bajarildi"
processing: "Amaliyotda"
preview: "Ko'rish"
-2
View File
@@ -250,7 +250,6 @@ noUsers: "Chưa có ai"
editProfile: "Sửa hồ sơ"
noteDeleteConfirm: "Bạn có chắc muốn xóa tút này?"
pinLimitExceeded: "Bạn không thể ghim bài viết nữa"
intro: "Đã cài đặt Misskey! Xin hãy tạo tài khoản admin."
done: "Xong"
processing: "Đang xử lý"
preview: "Xem trước"
@@ -783,7 +782,6 @@ thisIsExperimentalFeature: "Tính năng này đang trong quá trình thử nghi
developer: "Nhà phát triển"
makeExplorable: "Không hiện tôi trong \"Khám phá\""
makeExplorableDescription: "Nếu bạn tắt, tài khoản của bạn sẽ không hiện trong mục \"Khám phá\"."
showGapBetweenNotesInTimeline: "Hiện dải phân cách giữa các tút trên bảng tin"
duplicate: "Tạo bản sao"
left: "Bên trái"
center: "Giữa"
+7 -3
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "静音此服务器"
mediaSilenceThisInstance: "隐藏此服务器的媒体文件"
operations: "操作"
software: "软件"
softwareName: "软件名"
version: "版本"
metadata: "元数据"
withNFiles: "{n} 个文件"
@@ -250,7 +251,6 @@ noUsers: "无用户"
editProfile: "编辑资料"
noteDeleteConfirm: "确定要删除该帖子吗?"
pinLimitExceeded: "无法置顶更多了"
intro: "Misskey 的部署结束啦!创建管理员账号吧!"
done: "完成"
processing: "正在处理"
preview: "预览"
@@ -784,7 +784,6 @@ thisIsExperimentalFeature: "这是一项实验性功能。规范可能会变更
developer: "开发者"
makeExplorable: "使账号可见。"
makeExplorableDescription: "关闭时,账号不会显示在\"发现\"中。"
showGapBetweenNotesInTimeline: "时间线上的帖子分开显示。"
duplicate: "复制"
left: "左"
center: "中央"
@@ -1237,7 +1236,6 @@ showAvatarDecorations: "显示头像挂件"
releaseToRefresh: "松开以刷新"
refreshing: "刷新中"
pullDownToRefresh: "下拉以刷新"
disableStreamingTimeline: "禁止实时更新时间线"
useGroupedNotifications: "分组显示通知"
signupPendingError: "确认电子邮件时出现错误。链接可能已过期。"
cwNotationRequired: "在启用「隐藏内容」时必须输入注释"
@@ -1347,6 +1345,7 @@ readonly: "只读"
goToDeck: "返回至 Deck"
federationJobs: "联合作业"
driveAboutTip: "网盘可以显示以前上传的文件。<br>\n也可以在发布帖子时重复使用文件,或在发布帖子前预先上传文件。<br>\n<b>删除文件时,其将从至今为止所有用到该文件的地方(如帖子、页面、头像、横幅)消失。</b><br>\n也可以新建文件夹来整理文件。"
scrollToClose: "滑动并关闭"
_chat:
noMessagesYet: "还没有消息"
newMessage: "新消息"
@@ -1422,6 +1421,8 @@ _settings:
showNavbarSubButtons: "在导航栏中显示副按钮"
ifOn: "启用时"
ifOff: "关闭时"
enablePullToRefresh: "开启下拉刷新"
enablePullToRefresh_description: "使用鼠标时按下滚轮来拖动"
_chat:
showSenderName: "显示发送者的名字"
sendOnEnter: "回车键发送"
@@ -1429,6 +1430,7 @@ _preferencesProfile:
profileName: "配置名"
profileNameDescription: "请指定用于识别此设备的名称"
profileNameDescription2: "如「PC」、「手机」等"
manageProfiles: "管理配置文件"
_preferencesBackup:
autoBackup: "自动备份"
restoreFromBackup: "从备份恢复"
@@ -1467,6 +1469,7 @@ _delivery:
manuallySuspended: "手动停止中"
goneSuspended: "因服务器被删除而停止"
autoSuspendedForNotResponding: "因服务器无应答而停止"
softwareSuspended: "因有不可用的软件而停止"
_bubbleGame:
howToPlay: "游戏说明"
hold: "抓住"
@@ -1598,6 +1601,7 @@ _serverSettings:
openRegistration: "开放注册"
openRegistrationWarning: "开放注册有风险。建议仅当能够持续监控服务器并在出现问题时能够立即响应时才打开它。"
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "若在一段时间内没有检测到管理活动,为防止垃圾信息,此设定将自动关闭。"
deliverSuspendedSoftware: "不可用的软件"
_accountMigration:
moveFrom: "从别的账号迁移到此账户"
moveFromSub: "为另一个账户建立别名"
+8 -3
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "禁言此伺服器"
mediaSilenceThisInstance: "將這個伺服器的媒體設為禁言"
operations: "操作"
software: "軟體"
softwareName: "軟體名稱"
version: "版本"
metadata: "詮釋資料"
withNFiles: "{n} 個檔案"
@@ -250,7 +251,6 @@ noUsers: "沒有任何使用者"
editProfile: "編輯個人檔案"
noteDeleteConfirm: "確定刪除此貼文嗎?"
pinLimitExceeded: "不能置頂更多貼文了"
intro: "Misskey 部署完成!請建立管理員帳戶。"
done: "完成"
processing: "處理中"
preview: "預覽"
@@ -784,7 +784,6 @@ thisIsExperimentalFeature: "這是一項實驗性功能,其行為會隨需要
developer: "開發者"
makeExplorable: "使自己的帳戶更容易被找到"
makeExplorableDescription: "如果關閉,帳戶將不會被顯示在「探索」頁面中。"
showGapBetweenNotesInTimeline: "分開顯示時間軸上的貼文"
duplicate: "複製"
left: "左"
center: "置中"
@@ -1237,7 +1236,6 @@ showAvatarDecorations: "顯示頭像裝飾"
releaseToRefresh: "放開以更新內容"
refreshing: "載入更新中"
pullDownToRefresh: "往下拉來更新內容"
disableStreamingTimeline: "停用時間軸的即時更新"
useGroupedNotifications: "分組顯示通知訊息"
signupPendingError: "驗證您的電子郵件地址時出現問題。連結可能已過期。"
cwNotationRequired: "如果開啟「隱藏內容」,則需要註解說明。"
@@ -1347,6 +1345,7 @@ readonly: "唯讀"
goToDeck: "回去甲板"
federationJobs: "聯邦通訊作業"
driveAboutTip: "在「雲端硬碟」中,會顯示過去上傳的檔案列表。<br>\n可以在附加到貼文時重新利用,或者事先上傳之後再用於發布。<br>\n<b>請注意,刪除檔案後,之前使用過該檔案的所有地方(貼文、頁面、大頭貼、橫幅等)也會一併無法顯示。</b><br>\n也可以建立資料夾來整理檔案。"
scrollToClose: "用滾輪關閉"
_chat:
noMessagesYet: "尚無訊息"
newMessage: "新訊息"
@@ -1423,6 +1422,8 @@ _settings:
ifOn: "開啟時"
ifOff: "關閉時"
enableSyncThemesBetweenDevices: "在裝置之間同步已安裝的主題"
enablePullToRefresh: "下拉更新"
enablePullToRefresh_description: "使用滑鼠,按下並拖曳滾輪。"
_chat:
showSenderName: "顯示發送者的名稱"
sendOnEnter: "按下 Enter 發送訊息"
@@ -1430,6 +1431,7 @@ _preferencesProfile:
profileName: "設定檔案名稱"
profileNameDescription: "設定一個名稱來識別此裝置。"
profileNameDescription2: "例如:「主要個人電腦」、「智慧型手機」等"
manageProfiles: "管理個人檔案"
_preferencesBackup:
autoBackup: "自動備份"
restoreFromBackup: "從備份還原"
@@ -1468,6 +1470,7 @@ _delivery:
manuallySuspended: "手動暫停中"
goneSuspended: "因為伺服器刪除所以暫停中"
autoSuspendedForNotResponding: "因為伺服器沒有回應所以暫停中"
softwareSuspended: "此軟體因已停止發佈,目前無法使用"
_bubbleGame:
howToPlay: "玩法說明"
hold: "保留"
@@ -1599,6 +1602,8 @@ _serverSettings:
openRegistration: "允許建立帳戶"
openRegistrationWarning: "開放註冊伴隨著風險。 建議只有在伺服器受到持續監控,並準備好在出現問題時能立即處理的情況下才開放註冊。"
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "如果在一段期間內沒有偵測到任何審查員活動,此設定將自動關閉,以防止垃圾內容。"
deliverSuspendedSoftware: "已停止發佈的軟體"
deliverSuspendedSoftwareDescription: "由於脆弱性等原因,可以指定伺服器軟體的名稱與版本範圍來停止其發佈。這些版本資訊是由伺服器所提供,其可靠性無法保證。版本的指定可以使用 semver(語意化版本控制) 的範圍語法,但如果指定為 >= 2024.3.1,則像 2024.3.1-custom.0 這樣的自訂版本將不會被包含在內,因此建議使用 >= 2024.3.1-0 的方式來同時包含預發佈版本。"
_accountMigration:
moveFrom: "從其他帳戶遷移到這個帳戶"
moveFromSub: "為另一個帳戶建立別名"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "misskey",
"version": "2025.4.1-beta.9",
"version": "2025.5.1-alpha.0",
"codename": "nasubi",
"repository": {
"type": "git",
@@ -34,7 +34,7 @@
"watch": "pnpm dev",
"dev": "node scripts/dev.mjs",
"lint": "pnpm -r lint",
"cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
"cy:open": "pnpm cypress open --config-file=cypress.config.ts",
"cy:run": "pnpm cypress run",
"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
"e2e-dev-container": "ncp ./.config/cypress-devcontainer.yml ./.config/test.yml && pnpm start-server-and-test start:test http://localhost:61812 cy:run",
+8
View File
@@ -1,4 +1,5 @@
import tsParser from '@typescript-eslint/parser';
import globals from 'globals';
import sharedConfig from '../shared/eslint.config.js';
export default [
@@ -6,6 +7,13 @@ export default [
{
ignores: ['**/node_modules', 'built', '@types/**/*', 'migration'],
},
{
languageOptions: {
globals: {
...globals.node,
},
},
},
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env node
import child_process from 'node:child_process';
import path from 'node:path';
import url from 'node:url';
import semver from 'semver';
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const args = [];
args.push(...[
...semver.satisfies(process.version, '^20.17.0 || ^22.0.0') ? ['--no-experimental-require-module'] : [],
'--experimental-vm-modules',
'--experimental-import-meta-resolve',
path.join(__dirname, 'node_modules/jest/bin/jest.js'),
...process.argv.slice(2),
]);
child_process.spawn(process.execPath, args, { stdio: 'inherit' });
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class DeliverSuspendedSoftware1743403874305 {
name = 'DeliverSuspendedSoftware1743403874305'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "deliverSuspendedSoftware" jsonb NOT NULL DEFAULT '[]'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "deliverSuspendedSoftware"`);
}
}
@@ -3,11 +3,25 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { isConcurrentIndexMigrationEnabled } from "./js/migration-config.js";
export class CompositeNoteIndex1745378064470 {
name = 'CompositeNoteIndex1745378064470';
transaction = isConcurrentIndexMigrationEnabled() ? false : undefined;
async up(queryRunner) {
await queryRunner.query(`CREATE INDEX "IDX_724b311e6f883751f261ebe378" ON "note" ("userId", "id" DESC)`);
const concurrently = isConcurrentIndexMigrationEnabled();
if (concurrently) {
const hasValidIndex = await queryRunner.query(`SELECT indisvalid FROM pg_index INNER JOIN pg_class ON pg_index.indexrelid = pg_class.oid WHERE pg_class.relname = 'IDX_724b311e6f883751f261ebe378'`);
if (hasValidIndex.length === 0 || hasValidIndex[0].indisvalid !== true) {
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_724b311e6f883751f261ebe378"`);
await queryRunner.query(`CREATE INDEX CONCURRENTLY "IDX_724b311e6f883751f261ebe378" ON "note" ("userId", "id" DESC)`);
}
} else {
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_724b311e6f883751f261ebe378" ON "note" ("userId", "id" DESC)`);
}
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_5b87d9d19127bd5d92026017a7"`);
// Flush all cached Linear Scan Plans and redo statistics for composite index
// this is important for Postgres to learn that even in highly complex queries, using this index first can reduce the result set significantly
@@ -15,7 +29,8 @@ export class CompositeNoteIndex1745378064470 {
}
async down(queryRunner) {
const mayConcurrently = isConcurrentIndexMigrationEnabled() ? 'CONCURRENTLY' : '';
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_724b311e6f883751f261ebe378"`);
await queryRunner.query(`CREATE INDEX "IDX_5b87d9d19127bd5d92026017a7" ON "note" ("userId")`);
await queryRunner.query(`CREATE INDEX ${mayConcurrently} "IDX_5b87d9d19127bd5d92026017a7" ON "note" ("userId")`);
}
}
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class VisibleUserGeneratedContentsForNonLoggedInVisitors1746330901644 {
name = 'VisibleUserGeneratedContentsForNonLoggedInVisitors1746330901644'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "ugcVisibilityForVisitor" character varying(128) NOT NULL DEFAULT 'local'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "ugcVisibilityForVisitor"`);
}
}
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class SingleUserMode1746422049376 {
name = 'SingleUserMode1746422049376'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "singleUserMode" boolean NOT NULL DEFAULT false`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "singleUserMode"`);
}
}
@@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export function isConcurrentIndexMigrationEnabled() {
return process.env.MISSKEY_MIGRATION_CREATE_INDEX_CONCURRENTLY === '1';
}
+2
View File
@@ -1,6 +1,7 @@
import { DataSource } from 'typeorm';
import { loadConfig } from './built/config.js';
import { entities } from './built/postgres.js';
import { isConcurrentIndexMigrationEnabled } from "./migration/js/migration-config.js";
const config = loadConfig();
@@ -14,4 +15,5 @@ export default new DataSource({
extra: config.db.extra,
entities: entities,
migrations: ['migration/*.js'],
migrationsTransactionMode: isConcurrentIndexMigrationEnabled() ? 'each' : 'all',
});
+9 -8
View File
@@ -22,12 +22,12 @@
"typecheck": "tsc --noEmit && tsc -p test --noEmit && tsc -p test-federation --noEmit",
"eslint": "eslint --quiet \"{src,test-federation}/**/*.ts\"",
"lint": "pnpm typecheck && pnpm eslint",
"jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.unit.cjs",
"jest:e2e": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.e2e.cjs",
"jest:fed": "node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.fed.cjs",
"jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --config jest.config.unit.cjs",
"jest-and-coverage:e2e": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --config jest.config.e2e.cjs",
"jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache",
"jest": "cross-env NODE_ENV=test node ./jest.js --forceExit --config jest.config.unit.cjs",
"jest:e2e": "cross-env NODE_ENV=test node ./jest.js --forceExit --config jest.config.e2e.cjs",
"jest:fed": "node ./jest.js --forceExit --config jest.config.fed.cjs",
"jest-and-coverage": "cross-env NODE_ENV=test node ./jest.js --coverage --forceExit --config jest.config.unit.cjs",
"jest-and-coverage:e2e": "cross-env NODE_ENV=test node ./jest.js --coverage --forceExit --config jest.config.e2e.cjs",
"jest-clear": "cross-env NODE_ENV=test node ./jest.js --clearCache",
"test": "pnpm jest",
"test:e2e": "pnpm build && pnpm build:test && pnpm jest:e2e",
"test:fed": "pnpm jest:fed",
@@ -78,7 +78,7 @@
"@fastify/multipart": "9.0.3",
"@fastify/static": "8.1.1",
"@fastify/view": "10.0.2",
"@misskey-dev/sharp-read-bmp": "1.3.0",
"@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.2.1",
"@napi-rs/canvas": "0.1.69",
"@nestjs/common": "11.1.0",
@@ -168,7 +168,8 @@
"rxjs": "7.8.2",
"sanitize-html": "2.16.0",
"secure-json-parse": "3.0.2",
"sharp": "0.34.1",
"sharp": "0.33.5",
"semver": "7.7.1",
"slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
+7 -2
View File
@@ -24,8 +24,13 @@ const $config: Provider = {
const $db: Provider = {
provide: DI.db,
useFactory: async (config) => {
const db = createPostgresDataSource(config);
return await db.initialize();
try {
const db = createPostgresDataSource(config);
return await db.initialize();
} catch (e) {
console.log(e);
throw e;
}
},
inject: [DI.config],
};
@@ -9,87 +9,7 @@ import type { MiUser } from '@/models/User.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { NotificationService } from '@/core/NotificationService.js';
export const ACHIEVEMENT_TYPES = [
'notes1',
'notes10',
'notes100',
'notes500',
'notes1000',
'notes5000',
'notes10000',
'notes20000',
'notes30000',
'notes40000',
'notes50000',
'notes60000',
'notes70000',
'notes80000',
'notes90000',
'notes100000',
'login3',
'login7',
'login15',
'login30',
'login60',
'login100',
'login200',
'login300',
'login400',
'login500',
'login600',
'login700',
'login800',
'login900',
'login1000',
'passedSinceAccountCreated1',
'passedSinceAccountCreated2',
'passedSinceAccountCreated3',
'loggedInOnBirthday',
'loggedInOnNewYearsDay',
'noteClipped1',
'noteFavorited1',
'myNoteFavorited1',
'profileFilled',
'markedAsCat',
'following1',
'following10',
'following50',
'following100',
'following300',
'followers1',
'followers10',
'followers50',
'followers100',
'followers300',
'followers500',
'followers1000',
'collectAchievements30',
'viewAchievements3min',
'iLoveMisskey',
'foundTreasure',
'client30min',
'client60min',
'noteDeletedWithin1min',
'postedAtLateNight',
'postedAt0min0sec',
'selfQuote',
'htl20npm',
'viewInstanceChart',
'outputHelloWorldOnScratchpad',
'open3windows',
'driveFolderCircularReference',
'reactWithoutRead',
'clickedClickHere',
'justPlainLucky',
'setNameToSyuilo',
'cookieClicked',
'brainDiver',
'smashTestNotificationButton',
'tutorialCompleted',
'bubbleGameExplodingHead',
'bubbleGameDoubleExplodingHead',
] as const;
import { ACHIEVEMENT_TYPES } from '@/models/UserProfile.js';
@Injectable()
export class AchievementService {
+20
View File
@@ -578,6 +578,20 @@ export class ChatService {
@bindThis
public async deleteRoom(room: MiChatRoom, deleter?: MiUser) {
const memberships = (await this.chatRoomMembershipsRepository.findBy({ roomId: room.id })).map(m => ({
userId: m.userId,
})).concat({ // ownerはmembershipレコードを作らないため
userId: room.ownerId,
});
// 未読フラグ削除
const redisPipeline = this.redisClient.pipeline();
for (const membership of memberships) {
redisPipeline.del(`newRoomChatMessageExists:${membership.userId}:${room.id}`);
redisPipeline.srem(`newChatMessagesExists:${membership.userId}`, `room:${room.id}`);
}
await redisPipeline.exec();
await this.chatRoomsRepository.delete(room.id);
if (deleter) {
@@ -709,6 +723,12 @@ export class ChatService {
public async leaveRoom(userId: MiUser['id'], roomId: MiChatRoom['id']) {
const membership = await this.chatRoomMembershipsRepository.findOneByOrFail({ roomId, userId });
await this.chatRoomMembershipsRepository.delete(membership.id);
// 未読フラグを消す (「既読にする」というわけでもないのでreadメソッドは使わないでおく)
const redisPipeline = this.redisClient.pipeline();
redisPipeline.del(`newRoomChatMessageExists:${userId}:${roomId}`);
redisPipeline.srem(`newChatMessagesExists:${userId}`, `room:${roomId}`);
await redisPipeline.exec();
}
@bindThis
@@ -36,6 +36,7 @@ type TimelineOptions = {
excludeNoFiles?: boolean;
excludeReplies?: boolean;
excludePureRenotes: boolean;
ignoreAuthorFromUserSuspension?: boolean;
dbFallback: (untilId: string | null, sinceId: string | null, limit: number) => Promise<MiNote[]>,
};
@@ -139,6 +140,23 @@ export class FanoutTimelineEndpointService {
};
}
{
const parentFilter = filter;
filter = (note) => {
const noteJoined = note as MiNote & {
renoteUser: MiUser | null;
replyUser: MiUser | null;
};
if (!ps.ignoreAuthorFromUserSuspension) {
if (note.user!.isSuspended) return false;
}
if (note.userId !== note.renoteUserId && noteJoined.renoteUser?.isSuspended) return false;
if (note.userId !== note.replyUserId && noteJoined.replyUser?.isSuspended) return false;
return parentFilter(note);
};
}
const redisTimeline: MiNote[] = [];
let readFromRedis = 0;
let lastSuccessfulRate = 1; // rateをキャッシュする?
+45 -16
View File
@@ -43,29 +43,36 @@ export class QueryService {
) {
}
public makePaginationQuery<T extends ObjectLiteral>(q: SelectQueryBuilder<T>, sinceId?: string | null, untilId?: string | null, sinceDate?: number | null, untilDate?: number | null): SelectQueryBuilder<T> {
public makePaginationQuery<T extends ObjectLiteral>(
q: SelectQueryBuilder<T>,
sinceId?: string | null,
untilId?: string | null,
sinceDate?: number | null,
untilDate?: number | null,
targetColumn = 'id',
): SelectQueryBuilder<T> {
if (sinceId && untilId) {
q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: sinceId });
q.andWhere(`${q.alias}.id < :untilId`, { untilId: untilId });
q.orderBy(`${q.alias}.id`, 'DESC');
q.andWhere(`${q.alias}.${targetColumn} > :sinceId`, { sinceId: sinceId });
q.andWhere(`${q.alias}.${targetColumn} < :untilId`, { untilId: untilId });
q.orderBy(`${q.alias}.${targetColumn}`, 'DESC');
} else if (sinceId) {
q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: sinceId });
q.orderBy(`${q.alias}.id`, 'ASC');
q.andWhere(`${q.alias}.${targetColumn} > :sinceId`, { sinceId: sinceId });
q.orderBy(`${q.alias}.${targetColumn}`, 'ASC');
} else if (untilId) {
q.andWhere(`${q.alias}.id < :untilId`, { untilId: untilId });
q.orderBy(`${q.alias}.id`, 'DESC');
q.andWhere(`${q.alias}.${targetColumn} < :untilId`, { untilId: untilId });
q.orderBy(`${q.alias}.${targetColumn}`, 'DESC');
} else if (sinceDate && untilDate) {
q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: this.idService.gen(sinceDate) });
q.andWhere(`${q.alias}.id < :untilId`, { untilId: this.idService.gen(untilDate) });
q.orderBy(`${q.alias}.id`, 'DESC');
q.andWhere(`${q.alias}.${targetColumn} > :sinceId`, { sinceId: this.idService.gen(sinceDate) });
q.andWhere(`${q.alias}.${targetColumn} < :untilId`, { untilId: this.idService.gen(untilDate) });
q.orderBy(`${q.alias}.${targetColumn}`, 'DESC');
} else if (sinceDate) {
q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: this.idService.gen(sinceDate) });
q.orderBy(`${q.alias}.id`, 'ASC');
q.andWhere(`${q.alias}.${targetColumn} > :sinceId`, { sinceId: this.idService.gen(sinceDate) });
q.orderBy(`${q.alias}.${targetColumn}`, 'ASC');
} else if (untilDate) {
q.andWhere(`${q.alias}.id < :untilId`, { untilId: this.idService.gen(untilDate) });
q.orderBy(`${q.alias}.id`, 'DESC');
q.andWhere(`${q.alias}.${targetColumn} < :untilId`, { untilId: this.idService.gen(untilDate) });
q.orderBy(`${q.alias}.${targetColumn}`, 'DESC');
} else {
q.orderBy(`${q.alias}.id`, 'DESC');
q.orderBy(`${q.alias}.${targetColumn}`, 'DESC');
}
return q;
}
@@ -287,4 +294,26 @@ export class QueryService {
.andWhere(instanceSuspension('renoteUser'));
}
}
// Requirements: user replyUser renoteUser must be joined
@bindThis
public generateSuspendedUserQueryForNote(q: SelectQueryBuilder<any>, excludeAuthor?: boolean): void {
if (excludeAuthor) {
const brakets = (user: string) => new Brackets(qb => qb
.where(`note.${user}Id IS NULL`)
.orWhere(`user.id = ${user}.id`)
.orWhere(`${user}.isSuspended = FALSE`));
q
.andWhere(brakets('replyUser'))
.andWhere(brakets('renoteUser'));
} else {
const brakets = (user: string) => new Brackets(qb => qb
.where(`note.${user}Id IS NULL`)
.orWhere(`${user}.isSuspended = FALSE`));
q
.andWhere('user.isSuspended = FALSE')
.andWhere(brakets('replyUser'))
.andWhere(brakets('renoteUser'));
}
}
}
+8 -1
View File
@@ -235,6 +235,7 @@ export class SearchService {
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -297,11 +298,17 @@ export class SearchService {
])
: [new Set<string>(), new Set<string>()];
const query = this.notesRepository.createQueryBuilder('note');
const query = this.notesRepository.createQueryBuilder('note')
.innerJoinAndSelect('note.user', 'user')
.leftJoinAndSelect('note.reply', 'reply')
.leftJoinAndSelect('note.renote', 'renote')
.leftJoinAndSelect('reply.user', 'replyUser')
.leftJoinAndSelect('renote.user', 'renoteUser');
query.where('note.id IN (:...noteIds)', { noteIds: res.hits.map(x => x.id) });
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
const notes = (await query.getMany()).filter(note => {
if (me && isUserRelated(note, userIdsWhoBlockingMe)) return false;
+19 -1
View File
@@ -6,10 +6,12 @@
import { URL, domainToASCII } from 'node:url';
import { Inject, Injectable } from '@nestjs/common';
import RE2 from 're2';
import semver from 'semver';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { bindThis } from '@/decorators.js';
import { MiMeta } from '@/models/Meta.js';
import { MiMeta, SoftwareSuspension } from '@/models/Meta.js';
import { MiInstance } from '@/models/Instance.js';
@Injectable()
export class UtilityService {
@@ -143,4 +145,20 @@ export class UtilityService {
const host = this.extractDbHost(uri);
return this.isFederationAllowedHost(host);
}
@bindThis
public isDeliverSuspendedSoftware(software: Pick<MiInstance, 'softwareName' | 'softwareVersion'>): SoftwareSuspension | undefined {
if (software.softwareName == null) return undefined;
if (software.softwareVersion == null) {
// software version is null; suspend iff versionRange is *
return this.meta.deliverSuspendedSoftware.find(x =>
x.software === software.softwareName
&& x.versionRange.trim() === '*');
} else {
const softwareVersion = software.softwareVersion;
return this.meta.deliverSuspendedSoftware.find(x =>
x.software === software.softwareName
&& semver.satisfies(softwareVersion, x.versionRange, { includePrerelease: true }));
}
}
}
@@ -31,6 +31,7 @@ export class InstanceEntityService {
me?: { id: MiUser['id']; } | null | undefined,
): Promise<Packed<'FederationInstance'>> {
const iAmModerator = me ? await this.roleService.isModerator(me as MiUser) : false;
const softwareSuspended = this.utilityService.isDeliverSuspendedSoftware(instance);
return {
id: instance.id,
@@ -41,8 +42,8 @@ export class InstanceEntityService {
followingCount: instance.followingCount,
followersCount: instance.followersCount,
isNotResponding: instance.isNotResponding,
isSuspended: instance.suspensionState !== 'none',
suspensionState: instance.suspensionState,
isSuspended: instance.suspensionState !== 'none' || Boolean(softwareSuspended),
suspensionState: instance.suspensionState === 'none' && softwareSuspended ? 'softwareSuspended' : instance.suspensionState,
isBlocked: this.utilityService.isBlockedHost(this.meta.blockedHosts, instance.host),
softwareName: instance.softwareName,
softwareVersion: instance.softwareVersion,
@@ -429,6 +429,7 @@ export class NoteEntityService implements OnModuleInit {
userId: channel.userId,
} : undefined,
mentions: note.mentions.length > 0 ? note.mentions : undefined,
hasPoll: note.hasPoll || undefined,
uri: note.uri ?? undefined,
url: note.url ?? undefined,
@@ -593,4 +594,42 @@ export class NoteEntityService implements OnModuleInit {
relations: ['user'],
});
}
@bindThis
public async fetchDiffs(noteIds: MiNote['id'][]) {
if (noteIds.length === 0) return [];
const notes = await this.notesRepository.find({
where: {
id: In(noteIds),
},
select: {
id: true,
userHost: true,
reactions: true,
reactionAndUserPairCache: true,
},
});
const bufferedReactionsMap = this.meta.enableReactionsBuffering ? await this.reactionsBufferingService.getMany(noteIds) : null;
const packings = notes.map(note => {
const bufferedReactions = bufferedReactionsMap?.get(note.id);
//const reactionAndUserPairCache = note.reactionAndUserPairCache.concat(bufferedReactions.pairs.map(x => x.join('/')));
const reactions = this.reactionService.convertLegacyReactions(this.reactionsBufferingService.mergeReactions(note.reactions, bufferedReactions?.deltas ?? {}));
const reactionEmojiNames = Object.keys(reactions)
.filter(x => x.startsWith(':') && x.includes('@') && !x.includes('@.')) // リモートカスタム絵文字のみ
.map(x => this.reactionService.decodeReaction(x).reaction.replaceAll(':', ''));
return this.customEmojiService.populateEmojis(reactionEmojiNames, note.userHost).then(reactionEmojis => ({
id: note.id,
reactions,
reactionEmojis,
}));
});
return await Promise.all(packings);
}
}
+3
View File
@@ -67,6 +67,7 @@ import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessage
import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
import { packedAchievementNameSchema, packedAchievementSchema } from '@/models/json-schema/achievement.js';
export const refs = {
UserLite: packedUserLiteSchema,
@@ -78,6 +79,8 @@ export const refs = {
User: packedUserSchema,
UserList: packedUserListSchema,
Achievement: packedAchievementSchema,
AchievementName: packedAchievementNameSchema,
Ad: packedAdSchema,
Announcement: packedAnnouncementSchema,
App: packedAppSchema,
+3
View File
@@ -106,3 +106,6 @@ export class MiAntenna {
})
public excludeNotesInSensitiveChannel: boolean;
}
// Note for future developers: When you added a new column,
// You should update ExportAntennaProcessorService and ImportAntennaProcessorService
// to export and import antennas correctly.
+21
View File
@@ -659,9 +659,30 @@ export class MiMeta {
})
public federationHosts: string[];
@Column('varchar', {
length: 128,
default: 'local',
})
public ugcVisibilityForVisitor: 'all' | 'local' | 'none';
@Column('varchar', {
length: 64,
nullable: true,
})
public googleAnalyticsMeasurementId: string | null;
@Column('jsonb', {
default: [],
})
public deliverSuspendedSoftware: SoftwareSuspension[];
@Column('boolean', {
default: false,
})
public singleUserMode: boolean;
}
export type SoftwareSuspension = {
software: string,
versionRange: string,
};
+10 -1
View File
@@ -10,6 +10,16 @@ import { MiUser } from './User.js';
import { MiChannel } from './Channel.js';
import type { MiDriveFile } from './DriveFile.js';
// Note: When you create a new index for existing column of this table,
// it might be better to index concurrently under isConcurrentIndexMigrationEnabled flag
// by editing generated migration file since this table is very large,
// and it will make a long lock to create index in most cases.
// Please note that `CREATE INDEX CONCURRENTLY` is not supported in transaction,
// so you need to set `transaction = false` in migration if isConcurrentIndexMigrationEnabled() is true.
// Please refer 1745378064470-composite-note-index.js for example.
// You should not use `@Index({ concurrent: true })` decorator because database initialization for test will fail
// because it will always run CREATE INDEX in transaction based on decorators.
// Not appending `{ concurrent: true }` to `@Index` will not cause any problem in production,
@Index(['userId', 'id'])
@Entity('note')
export class MiNote {
@@ -229,7 +239,6 @@ export class MiNote {
comment: '[Denormalized]',
})
public renoteUserHost: string | null;
//#endregion
constructor(data: Partial<MiNote>) {
if (data == null) return;
+82 -1
View File
@@ -274,7 +274,7 @@ export class MiUserProfile {
default: [],
})
public achievements: {
name: string;
name: typeof ACHIEVEMENT_TYPES[number];
unlockedAt: number;
}[];
@@ -295,3 +295,84 @@ export class MiUserProfile {
}
}
}
export const ACHIEVEMENT_TYPES = [
'notes1',
'notes10',
'notes100',
'notes500',
'notes1000',
'notes5000',
'notes10000',
'notes20000',
'notes30000',
'notes40000',
'notes50000',
'notes60000',
'notes70000',
'notes80000',
'notes90000',
'notes100000',
'login3',
'login7',
'login15',
'login30',
'login60',
'login100',
'login200',
'login300',
'login400',
'login500',
'login600',
'login700',
'login800',
'login900',
'login1000',
'passedSinceAccountCreated1',
'passedSinceAccountCreated2',
'passedSinceAccountCreated3',
'loggedInOnBirthday',
'loggedInOnNewYearsDay',
'noteClipped1',
'noteFavorited1',
'myNoteFavorited1',
'profileFilled',
'markedAsCat',
'following1',
'following10',
'following50',
'following100',
'following300',
'followers1',
'followers10',
'followers50',
'followers100',
'followers300',
'followers500',
'followers1000',
'collectAchievements30',
'viewAchievements3min',
'iLoveMisskey',
'foundTreasure',
'client30min',
'client60min',
'noteDeletedWithin1min',
'postedAtLateNight',
'postedAt0min0sec',
'selfQuote',
'htl20npm',
'viewInstanceChart',
'outputHelloWorldOnScratchpad',
'open3windows',
'driveFolderCircularReference',
'reactWithoutRead',
'clickedClickHere',
'justPlainLucky',
'setNameToSyuilo',
'cookieClicked',
'brainDiver',
'smashTestNotificationButton',
'tutorialCompleted',
'bubbleGameExplodingHead',
'bubbleGameDoubleExplodingHead',
] as const;
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { ACHIEVEMENT_TYPES } from '@/models/UserProfile.js';
export const packedAchievementNameSchema = {
type: 'string',
enum: ACHIEVEMENT_TYPES,
optional: false,
} as const;
export const packedAchievementSchema = {
type: 'object',
properties: {
name: {
ref: 'AchievementName',
},
unlockedAt: {
type: 'number',
optional: false,
},
},
} as const;
@@ -48,7 +48,7 @@ export const packedFederationInstanceSchema = {
suspensionState: {
type: 'string',
nullable: false, optional: false,
enum: ['none', 'manuallySuspended', 'goneSuspended', 'autoSuspendedForNotResponding'],
enum: ['none', 'manuallySuspended', 'goneSuspended', 'autoSuspendedForNotResponding', 'softwareSuspended'],
},
isBlocked: {
type: 'boolean',
@@ -256,6 +256,10 @@ export const packedNoteSchema = {
type: 'number',
optional: true, nullable: false,
},
hasPoll: {
type: 'boolean',
optional: true, nullable: false,
},
myReaction: {
type: 'string',
@@ -3,7 +3,6 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { ACHIEVEMENT_TYPES } from '@/core/AchievementService.js';
import { notificationTypes, userExportableEntities } from '@/types.js';
const baseSchema = {
@@ -312,9 +311,7 @@ export const packedNotificationSchema = {
enum: ['achievementEarned'],
},
achievement: {
type: 'string',
optional: false, nullable: false,
enum: ACHIEVEMENT_TYPES,
ref: 'AchievementName',
},
},
}, {
@@ -630,18 +630,7 @@ export const packedMeDetailedOnlySchema = {
type: 'array',
nullable: false, optional: false,
items: {
type: 'object',
nullable: false, optional: false,
properties: {
name: {
type: 'string',
nullable: false, optional: false,
},
unlockedAt: {
type: 'number',
nullable: false, optional: false,
},
},
ref: 'Achievement',
},
},
loggedInDays: {
@@ -71,6 +71,15 @@ export class DeliverProcessorService {
return 'skip (suspended)';
}
const i = await (this.meta.enableStatsForFederatedInstances
? this.federatedInstanceService.fetchOrRegister(host)
: this.federatedInstanceService.fetch(host));
// suspend server by software
if (i != null && this.utilityService.isDeliverSuspendedSoftware(i)) {
return 'skip (software suspended)';
}
try {
await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content, job.data.digest);
@@ -79,10 +88,6 @@ export class DeliverProcessorService {
// Update instance stats
process.nextTick(async () => {
const i = await (this.meta.enableStatsForFederatedInstances
? this.federatedInstanceService.fetchOrRegister(host)
: this.federatedInstanceService.fetch(host));
if (i == null) return;
if (i.isNotResponding) {
@@ -15,6 +15,7 @@ import { bindThis } from '@/decorators.js';
import { createTemp } from '@/misc/create-temp.js';
import { UtilityService } from '@/core/UtilityService.js';
import { NotificationService } from '@/core/NotificationService.js';
import { ExportedAntenna } from '@/queue/processors/ImportAntennasProcessorService.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type { DBExportAntennasData } from '../types.js';
import type * as Bull from 'bullmq';
@@ -86,7 +87,8 @@ export class ExportAntennasProcessorService {
excludeBots: antenna.excludeBots,
withReplies: antenna.withReplies,
withFile: antenna.withFile,
}));
excludeNotesInSensitiveChannel: antenna.excludeNotesInSensitiveChannel,
} satisfies Required<ExportedAntenna>));
if (antennas.length - 1 !== index) {
write(', ');
}
@@ -11,17 +11,18 @@ import Logger from '@/logger.js';
import type { AntennasRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { Schema, SchemaType } from '@/misc/json-schema.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import { DBAntennaImportJobData } from '../types.js';
import type * as Bull from 'bullmq';
const Ajv = _Ajv.default;
const validate = new Ajv().compile({
const exportedAntennaSchema = {
type: 'object',
properties: {
name: { type: 'string', minLength: 1, maxLength: 100 },
src: { type: 'string', enum: ['home', 'all', 'users', 'list'] },
src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'users_blacklist'] },
userListAccts: {
type: 'array',
items: {
@@ -47,9 +48,14 @@ const validate = new Ajv().compile({
excludeBots: { type: 'boolean' },
withReplies: { type: 'boolean' },
withFile: { type: 'boolean' },
excludeNotesInSensitiveChannel: { type: 'boolean' },
},
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
});
} as const satisfies Schema;
export type ExportedAntenna = SchemaType<typeof exportedAntennaSchema>;
const validate = new Ajv().compile<ExportedAntenna>(exportedAntennaSchema);
@Injectable()
export class ImportAntennasProcessorService {
@@ -91,6 +97,7 @@ export class ImportAntennasProcessorService {
excludeBots: antenna.excludeBots,
withReplies: antenna.withReplies,
withFile: antenna.withFile,
excludeNotesInSensitiveChannel: antenna.excludeNotesInSensitiveChannel,
});
this.logger.succ('Antenna created: ' + result.id);
this.globalEventService.publishInternalEvent('antennaCreated', result);
+11 -5
View File
@@ -7,7 +7,7 @@ import cluster from 'node:cluster';
import * as fs from 'node:fs';
import { fileURLToPath } from 'node:url';
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import Fastify, { FastifyInstance } from 'fastify';
import Fastify, { type FastifyInstance } from 'fastify';
import fastifyStatic from '@fastify/static';
import fastifyRawBody from 'fastify-raw-body';
import { IsNull } from 'typeorm';
@@ -73,7 +73,7 @@ export class ServerService implements OnApplicationShutdown {
}
@bindThis
public async launch() {
public async launch(): Promise<void> {
const fastify = Fastify({
trustProxy: true,
logger: false,
@@ -133,8 +133,8 @@ export class ServerService implements OnApplicationShutdown {
reply.header('content-type', 'text/plain; charset=utf-8');
reply.header('link', `<${encodeURI(location)}>; rel="canonical"`);
done(null, [
'Refusing to relay remote ActivityPub object lookup.',
'',
"Refusing to relay remote ActivityPub object lookup.",
"",
`Please remove 'application/activity+json' and 'application/ld+json' from the Accept header or fetch using the authoritative URL at ${location}.`,
].join('\n'));
});
@@ -301,7 +301,6 @@ export class ServerService implements OnApplicationShutdown {
}
await fastify.ready();
return fastify;
}
@bindThis
@@ -310,6 +309,13 @@ export class ServerService implements OnApplicationShutdown {
await this.#fastify.close();
}
/**
* Get the Fastify instance for testing.
*/
public get fastify(): FastifyInstance {
return this.#fastify;
}
@bindThis
async onApplicationShutdown(signal: string): Promise<void> {
await this.dispose();
+54 -112
View File
@@ -6,11 +6,8 @@
import { randomUUID } from 'node:crypto';
import * as fs from 'node:fs';
import * as stream from 'node:stream/promises';
import { Transform } from 'node:stream';
import { type MultipartFile } from '@fastify/multipart';
import { Inject, Injectable } from '@nestjs/common';
import * as Sentry from '@sentry/node';
import { AttachmentFile } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { getIpHash } from '@/misc/get-ip-hash.js';
import type { MiLocalUser, MiUser } from '@/models/User.js';
@@ -19,7 +16,7 @@ import type Logger from '@/logger.js';
import type { MiMeta, UserIpsRepository } from '@/models/_.js';
import { createTemp } from '@/misc/create-temp.js';
import { bindThis } from '@/decorators.js';
import { type RolePolicies, RoleService } from '@/core/RoleService.js';
import { RoleService } from '@/core/RoleService.js';
import type { Config } from '@/config.js';
import { ApiError } from './error.js';
import { RateLimiterService } from './RateLimiterService.js';
@@ -203,6 +200,18 @@ export class ApiCallService implements OnApplicationShutdown {
return;
}
const [path, cleanup] = await createTemp();
await stream.pipeline(multipartData.file, fs.createWriteStream(path));
// ファイルサイズが制限を超えていた場合
// なお truncated はストリームを読み切ってからでないと機能しないため、stream.pipeline より後にある必要がある
if (multipartData.file.truncated) {
cleanup();
reply.code(413);
reply.send();
return;
}
const fields = {} as Record<string, unknown>;
for (const [k, v] of Object.entries(multipartData.fields)) {
fields[k] = typeof v === 'object' && 'value' in v ? v.value : undefined;
@@ -217,7 +226,10 @@ export class ApiCallService implements OnApplicationShutdown {
return;
}
this.authenticateService.authenticate(token).then(([user, app]) => {
this.call(endpoint, user, app, fields, multipartData, request).then((res) => {
this.call(endpoint, user, app, fields, {
name: multipartData.filename,
path: path,
}, request).then((res) => {
this.send(reply, res);
}).catch((err: ApiError) => {
this.#sendApiError(reply, err);
@@ -282,7 +294,10 @@ export class ApiCallService implements OnApplicationShutdown {
user: MiLocalUser | null | undefined,
token: MiAccessToken | null | undefined,
data: any,
multipartFile: MultipartFile | null,
file: {
name: string;
path: string;
} | null,
request: FastifyRequest<{ Body: Record<string, unknown> | undefined, Querystring: Record<string, unknown> }>,
) {
const isSecure = user != null && token == null;
@@ -356,37 +371,6 @@ export class ApiCallService implements OnApplicationShutdown {
}
}
// Cast non JSON input
if ((ep.meta.requireFile || request.method === 'GET') && ep.params.properties) {
for (const k of Object.keys(ep.params.properties)) {
const param = ep.params.properties![k];
if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') {
try {
data[k] = JSON.parse(data[k]);
} catch (e) {
throw new ApiError({
message: 'Invalid param.',
code: 'INVALID_PARAM',
id: '0b5f1631-7c1a-41a6-b399-cce335f34d85',
}, {
param: k,
reason: `cannot cast to ${param.type}`,
});
}
}
}
}
if (token && ((ep.meta.kind && !token.permission.some(p => p === ep.meta.kind))
|| (!ep.meta.kind && (ep.meta.requireCredential || ep.meta.requireModerator || ep.meta.requireAdmin)))) {
throw new ApiError({
message: 'Your app does not have the necessary permissions to use this endpoint.',
code: 'PERMISSION_DENIED',
kind: 'permission',
id: '1370e5b7-d4eb-4566-bb1d-7748ee6a1838',
});
}
if ((ep.meta.requireModerator || ep.meta.requireAdmin) && (this.meta.rootUserId !== user!.id)) {
const myRoles = await this.roleService.getUserRoles(user!.id);
if (ep.meta.requireModerator && !myRoles.some(r => r.isModerator || r.isAdministrator)) {
@@ -420,91 +404,49 @@ export class ApiCallService implements OnApplicationShutdown {
}
}
let attachmentFile: AttachmentFile | null = null;
let cleanup = () => {};
if (ep.meta.requireFile && request.method === 'POST' && multipartFile) {
const policies = await this.roleService.getUserPolicies(user!.id);
const result = await this.handleAttachmentFile(
Math.min((policies.maxFileSizeMb * 1024 * 1024), this.config.maxFileSize),
multipartFile,
);
attachmentFile = result.attachmentFile;
cleanup = result.cleanup;
if (token && ((ep.meta.kind && !token.permission.some(p => p === ep.meta.kind))
|| (!ep.meta.kind && (ep.meta.requireCredential || ep.meta.requireModerator || ep.meta.requireAdmin)))) {
throw new ApiError({
message: 'Your app does not have the necessary permissions to use this endpoint.',
code: 'PERMISSION_DENIED',
kind: 'permission',
id: '1370e5b7-d4eb-4566-bb1d-7748ee6a1838',
});
}
// Cast non JSON input
if ((ep.meta.requireFile || request.method === 'GET') && ep.params.properties) {
for (const k of Object.keys(ep.params.properties)) {
const param = ep.params.properties![k];
if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') {
try {
data[k] = JSON.parse(data[k]);
} catch (e) {
throw new ApiError({
message: 'Invalid param.',
code: 'INVALID_PARAM',
id: '0b5f1631-7c1a-41a6-b399-cce335f34d85',
}, {
param: k,
reason: `cannot cast to ${param.type}`,
});
}
}
}
}
// API invoking
if (this.config.sentryForBackend) {
return await Sentry.startSpan({
name: 'API: ' + ep.name,
}, () => {
return ep.exec(data, user, token, attachmentFile, request.ip, request.headers)
.catch((err: Error) => this.#onExecError(ep, data, err, user?.id))
.finally(() => cleanup());
});
}, () => ep.exec(data, user, token, file, request.ip, request.headers)
.catch((err: Error) => this.#onExecError(ep, data, err, user?.id)));
} else {
return await ep.exec(data, user, token, attachmentFile, request.ip, request.headers)
.catch((err: Error) => this.#onExecError(ep, data, err, user?.id))
.finally(() => cleanup());
return await ep.exec(data, user, token, file, request.ip, request.headers)
.catch((err: Error) => this.#onExecError(ep, data, err, user?.id));
}
}
@bindThis
private async handleAttachmentFile(
fileSizeLimit: number,
multipartFile: MultipartFile,
) {
function createTooLongError() {
return new ApiError({
httpStatusCode: 413,
kind: 'client',
message: 'File size is too large.',
code: 'FILE_SIZE_TOO_LARGE',
id: 'ff827ce8-9b4b-4808-8511-422222a3362f',
});
}
function createLimitStream(limit: number) {
let total = 0;
return new Transform({
transform(chunk, _, callback) {
total += chunk.length;
if (total > limit) {
callback(createTooLongError());
} else {
callback(null, chunk);
}
},
});
}
const [path, cleanup] = await createTemp();
try {
await stream.pipeline(
multipartFile.file,
createLimitStream(fileSizeLimit),
fs.createWriteStream(path),
);
// ファイルサイズが制限を超えていた場合
// なお truncated はストリームを読み切ってからでないと機能しないため、stream.pipeline より後にある必要がある
if (multipartFile.file.truncated) {
throw createTooLongError();
}
} catch (err) {
cleanup();
throw err;
}
return {
attachmentFile: {
name: multipartFile.filename,
path,
},
cleanup,
};
}
@bindThis
public dispose(): void {
clearInterval(this.userIpHistoriesClearIntervalId);
@@ -21,23 +21,23 @@ ajv.addFormat('misskey:id', /^[a-zA-Z0-9]+$/);
export type Response = Record<string, any> | void;
export type AttachmentFile = {
type File = {
name: string | null;
path: string;
};
// TODO: paramsの型をT['params']のスキーマ定義から推論する
type Executor<T extends IEndpointMeta, Ps extends Schema> =
(params: SchemaType<Ps>, user: T['requireCredential'] extends true ? MiLocalUser : MiLocalUser | null, token: MiAccessToken | null, file?: AttachmentFile, cleanup?: () => any, ip?: string | null, headers?: Record<string, string> | null) =>
Promise<T['res'] extends undefined ? Response : SchemaType<NonNullable<T['res']>>>;
(params: SchemaType<Ps>, user: T['requireCredential'] extends true ? MiLocalUser : MiLocalUser | null, token: MiAccessToken | null, file?: File, cleanup?: () => any, ip?: string | null, headers?: Record<string, string> | null) =>
Promise<T['res'] extends undefined ? Response : SchemaType<NonNullable<T['res']>>>;
export abstract class Endpoint<T extends IEndpointMeta, Ps extends Schema> {
public exec: (params: any, user: T['requireCredential'] extends true ? MiLocalUser : MiLocalUser | null, token: MiAccessToken | null, file?: AttachmentFile, ip?: string | null, headers?: Record<string, string> | null) => Promise<any>;
public exec: (params: any, user: T['requireCredential'] extends true ? MiLocalUser : MiLocalUser | null, token: MiAccessToken | null, file?: File, ip?: string | null, headers?: Record<string, string> | null) => Promise<any>;
constructor(meta: T, paramDef: Ps, cb: Executor<T, Ps>) {
const validate = ajv.compile(paramDef);
this.exec = (params: any, user: T['requireCredential'] extends true ? MiLocalUser : MiLocalUser | null, token: MiAccessToken | null, file?: AttachmentFile, ip?: string | null, headers?: Record<string, string> | null) => {
this.exec = (params: any, user: T['requireCredential'] extends true ? MiLocalUser : MiLocalUser | null, token: MiAccessToken | null, file?: File, ip?: string | null, headers?: Record<string, string> | null) => {
let cleanup: undefined | (() => void) = undefined;
if (meta.requireFile) {
@@ -323,6 +323,7 @@ export * as 'notes/replies' from './endpoints/notes/replies.js';
export * as 'notes/search' from './endpoints/notes/search.js';
export * as 'notes/search-by-tag' from './endpoints/notes/search-by-tag.js';
export * as 'notes/show' from './endpoints/notes/show.js';
export * as 'notes/show-partial-bulk' from './endpoints/notes/show-partial-bulk.js';
export * as 'notes/state' from './endpoints/notes/state.js';
export * as 'notes/thread-muting/create' from './endpoints/notes/thread-muting/create.js';
export * as 'notes/thread-muting/delete' from './endpoints/notes/thread-muting/delete.js';
@@ -528,6 +528,33 @@ export const meta = {
optional: false, nullable: false,
},
},
deliverSuspendedSoftware: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
software: {
type: 'string',
optional: false, nullable: false,
},
versionRange: {
type: 'string',
optional: false, nullable: false,
},
},
},
},
singleUserMode: {
type: 'boolean',
optional: false, nullable: false,
},
ugcVisibilityForVisitor: {
type: 'string',
enum: ['all', 'local', 'none'],
optional: false, nullable: false,
},
},
},
} as const;
@@ -672,6 +699,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
federation: instance.federation,
federationHosts: instance.federationHosts,
deliverSuspendedSoftware: instance.deliverSuspendedSoftware,
singleUserMode: instance.singleUserMode,
ugcVisibilityForVisitor: instance.ugcVisibilityForVisitor,
};
});
}
@@ -185,6 +185,22 @@ export const paramDef = {
type: 'string',
},
},
deliverSuspendedSoftware: {
type: 'array',
items: {
type: 'object',
properties: {
software: { type: 'string' },
versionRange: { type: 'string' },
},
required: ['software', 'versionRange'],
},
},
singleUserMode: { type: 'boolean' },
ugcVisibilityForVisitor: {
type: 'string',
enum: ['all', 'local', 'none'],
},
},
required: [],
} as const;
@@ -671,10 +687,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.federation = ps.federation;
}
if (ps.deliverSuspendedSoftware !== undefined) {
set.deliverSuspendedSoftware = ps.deliverSuspendedSoftware;
}
if (Array.isArray(ps.federationHosts)) {
set.federationHosts = ps.federationHosts.filter(Boolean).map(x => x.toLowerCase());
}
if (ps.singleUserMode !== undefined) {
set.singleUserMode = ps.singleUserMode;
}
if (ps.ugcVisibilityForVisitor !== undefined) {
set.ugcVisibilityForVisitor = ps.ugcVisibilityForVisitor;
}
const before = await this.metaService.fetch(true);
await this.metaService.update(set);
@@ -112,6 +112,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// https://github.com/misskey-dev/misskey/pull/15346#discussion_r1929950255
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -48,7 +48,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.channelFollowingsRepository.createQueryBuilder(), ps.sinceId, ps.untilId)
const query = this.queryService
.makePaginationQuery(
this.channelFollowingsRepository.createQueryBuilder(),
ps.sinceId,
ps.untilId,
null,
null,
'followeeId',
)
.andWhere({ followerId: me.id });
const followings = await query
@@ -122,6 +122,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('note.channel', 'channel');
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
if (me) {
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -85,9 +85,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser')
.andWhere('clipNote.clipId = :clipId', { clipId: clip.id });
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
// this.queryService.generateSuspendedUserQueryForNote(query); // To avoid problems with removing notes, ignoring suspended user for now
if (me) {
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
}
@@ -61,6 +61,7 @@ export const meta = {
message: 'Cannot upload the file because it exceeds the maximum file size.',
code: 'MAX_FILE_SIZE_EXCEEDED',
id: 'b9d8c348-33f0-4673-b9a9-5d4da058977a',
httpStatusCode: 413,
},
},
} as const;
@@ -5,7 +5,8 @@
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { AchievementService, ACHIEVEMENT_TYPES } from '@/core/AchievementService.js';
import { AchievementService } from '@/core/AchievementService.js';
import { ACHIEVEMENT_TYPES } from '@/models/UserProfile.js';
export const meta = {
requireCredential: true,
@@ -71,6 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
if (me) {
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -97,6 +97,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('note.channel', 'channel');
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
const notes = (await query.getMany()).filter(note => {
if (me && isUserRelated(note, userIdsWhoBlockingMe)) return false;
@@ -244,6 +244,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
@@ -157,6 +157,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
if (me) this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
@@ -73,6 +73,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateMutedNoteThreadQuery(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -73,6 +73,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -57,6 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -82,6 +82,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateSuspendedUserQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);

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