Compare commits

...

26 Commits

Author SHA1 Message Date
github-actions[bot] 978ae706eb Release: 2025.6.2 2025-06-16 08:58:31 +00:00
syuilo 824643a44e [skip ci] Update CHANGELOG.md 2025-06-16 17:57:09 +09:00
github-actions[bot] 213c569242 Bump version to 2025.6.2-alpha.0 2025-06-16 05:08:24 +00:00
syuilo a1cf2d3074 New Crowdin updates (#16192)
* New translations ja-jp.yml (Chinese Traditional)

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

* New translations ja-jp.yml (Catalan)

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

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Simplified)
2025-06-16 14:07:48 +09:00
syuilo 4ea7c76c02 fix(frontend): キャッシュを削除しないとクライアントが使用できないことがある問題を修正 2025-06-16 13:55:27 +09:00
github-actions[bot] 1782a353d3 [skip ci] Update CHANGELOG.md (prepend template) 2025-06-16 02:33:19 +00:00
github-actions[bot] c69a13b592 Release: 2025.6.1 2025-06-16 02:33:14 +00:00
syuilo 40e35c051a Update CHANGELOG.md 2025-06-15 11:10:03 +09:00
syuilo b93717be33 Update CHANGELOG.md
Co-authored-by: おさむのひと <46447427+samunohito@users.noreply.github.com>
2025-06-15 11:08:53 +09:00
syuilo fe805fb7f0 enhance(frontend/image-effector): tweak fxs 2025-06-15 11:06:46 +09:00
syuilo e9af9d4451 enhance(frontend/image-effector): tweak fxs 2025-06-15 10:57:29 +09:00
syuilo ce90fee586 enhance(frontend/image-effector): add blockNoise fx 2025-06-15 10:55:11 +09:00
syuilo 5bec8ba6b0 enhance(frontend/image-effector): tweak fxs 2025-06-15 10:19:42 +09:00
syuilo 3dbfd80d65 enhance(frontend/image-effector): tweak colorAdjust fx 2025-06-15 09:25:57 +09:00
syuilo b33eeb1366 enhance(frontend/image-effector): tweak distort fx 2025-06-15 08:47:59 +09:00
syuilo 420756d744 Update CHANGELOG.md 2025-06-14 19:50:56 +09:00
かっこかり 32d721abf1 refactor(frontend): checkWordMuteの返り値が誤っている問題を修正 (#16188)
* refactor(frontend): checkWordMuteの返り値が誤っている問題を修正

* fix lint
2025-06-14 16:08:14 +09:00
github-actions[bot] 8ea6aa2ef3 Bump version to 2025.6.1-rc.0 2025-06-14 03:16:12 +00:00
syuilo bc07b79a23 fix(frontend): デッキのタイムラインカラムで新着ノート時のサウンドが再生されない問題を修正
Fix #16164
2025-06-14 11:36:42 +09:00
syuilo aae7961540 New Crowdin updates (#16187)
* New translations ja-jp.yml (Chinese Simplified)

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

* New translations ja-jp.yml (Chinese Simplified)
2025-06-13 10:31:14 +09:00
github-actions[bot] 1ad32990cb Bump version to 2025.6.1-beta.2 2025-06-12 10:07:07 +00:00
zyoshoka 89db7b3fa8 fix(frontend): display reactions correctly in welcome timeline (#16186) 2025-06-12 19:05:24 +09:00
syuilo 151121a567 New Crowdin updates (#16183)
* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Italian)
2025-06-12 17:34:12 +09:00
mochi33i 966e0812f5 fix(misskey-js) : misskey-jsの drive/file/create でファイルアップロードができない問題を修正 (#16028)
* fix(misskey-js): drive/file/createが動かない問題を修正

* CHANGELOG.mdに修正内容を追加
2025-06-12 16:54:59 +09:00
syuilo d378156212 Update CHANGELOG.md 2025-06-12 16:08:07 +09:00
renovate[bot] 568021498f fix(deps): update [root] update dependencies (#16142)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-11 14:39:49 +09:00
36 changed files with 575 additions and 588 deletions
+13 -5
View File
@@ -1,13 +1,18 @@
## 2025.6.2
### Client
- Fix: キャッシュを削除しないとクライアントが使用できないことがある問題を修正
- 翻訳の更新
## 2025.6.1
### Note
- Misskey Webプラグインのnote_view_interruptorは不具合の影響により現在一時的に無効化されています。
### General
-
- AiScript Misskey拡張APIMisskey Webプラグイン)の[note_view_interruptor](https://misskey-hub.net/ja/docs/for-developers/plugin/plugin-api-reference/#pluginregister_note_view_interruptorfn)は不具合の影響により現在一時的に無効化されています。
- Misskey Web投稿フォームのプレビュー切り替えは「...」メニュー内に配置されました
### Client
- Feat: 画像にウォーターマークを付与できるようになりました
- Feat: 画像の加工ができるようになりました(実験的)
- Enhance: ノートのリアクション一覧で、押せるリアクションを優先して表示できるようにするオプションを追加
- Enhance: 全てのチャットメッセージを既読にできるように(設定→その他)
- Enhance: ミュートした絵文字をデバイス間で同期できるように
@@ -15,13 +20,16 @@
- Fix: コントロールパネルのファイル欄などのデザインが崩れている問題を修正
- Fix: ユーザーの検索結果を追加で読み込むことができない問題を修正
- Fix: タッチ操作時にチャートのツールチップが消えなくなる場合がある問題を修正
- Fix: Plugin:register_note_view_interruptor()によるノートの書き換えが機能しない問題を修正
- Fix: ウェルカムタイムラインでリアクションが表示されない問題を修正
- Fix: デッキのタイムラインカラムで新着ノート時のサウンドが再生されない問題を修正
### Server
- Feat: 全てのチャットメッセージを既読にするAPIを追加(chat/read-all)
- Fix: アカウント削除が正常に行われないことがあった問題を修正
- Fix: outboxのページネーションが正しく行われない問題を修正
### Misskey.js
- Fix: misskey-jsの drive/file/create でファイルアップロードができない問題を修正
## 2025.6.0
+2
View File
@@ -3169,3 +3169,5 @@ _imageEffector:
stripe: "Bandes"
polkadot: "Lunars"
checker: "Escacs"
blockNoise: "Bloqueig de soroll"
tearing: "Trencament d'imatge "
+4
View File
@@ -2465,6 +2465,8 @@ _visibility:
disableFederation: "Defederate"
disableFederationDescription: "Don't transmit to other instances"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "There are files that have not been uploaded, do you want to discard them and close the form?"
uploaderTip: "The file has not yet been uploaded. From the file menu, you can rename, crop images, watermark and compress or uncompress the file. Files are automatically uploaded when you publish a note."
replyPlaceholder: "Reply to this note..."
quotePlaceholder: "Quote this note..."
channelPlaceholder: "Post to a channel..."
@@ -3167,3 +3169,5 @@ _imageEffector:
stripe: "Stripes"
polkadot: "Polkadot"
checker: "Checker"
blockNoise: "Block Noise"
tearing: "Tearing"
+2
View File
@@ -3169,3 +3169,5 @@ _imageEffector:
stripe: "Rayas"
polkadot: "Lunares"
checker: "Corrector"
blockNoise: "Bloquear Ruido"
tearing: "Rasgado de Imagen (Tearing)"
+8
View File
@@ -12220,6 +12220,14 @@ export interface Locale extends ILocale {
*
*/
"checker": string;
/**
*
*/
"blockNoise": string;
/**
*
*/
"tearing": string;
};
};
}
+5 -2
View File
@@ -582,7 +582,7 @@ sounds: "Impostazioni suoni"
sound: "Suono"
notificationSoundSettings: "Preferenze di notifica"
listen: "Ascolta"
none: "Nessuno"
none: "Nessuna"
showInPage: "Visualizza in pagina"
popout: "Finestra pop-out"
volume: "Volume"
@@ -1342,7 +1342,7 @@ information: "Informazioni"
chat: "Chat"
migrateOldSettings: "Migrare le vecchie impostazioni"
migrateOldSettings_description: "Di solito, viene fatto automaticamente. Se per qualche motivo non fossero migrate con successo, è possibile avviare il processo di migrazione manualmente, sovrascrivendo le configurazioni attuali."
compress: "Comprimi"
compress: "Compressione"
right: "Destra"
bottom: "Sotto"
top: "Sopra"
@@ -1351,6 +1351,7 @@ settingsMigrating: "Migrazione delle impostazioni. Attendere prego ... (Puoi anc
readonly: "Sola lettura"
goToDeck: "Torna al Deck"
federationJobs: "Coda di federazione"
driveAboutTip: "Il Drive mostra l'elenco di file caricati in passato. Puoi organizzarli in cartelle, riusarli allegandoli ad altre note, o caricarli in anticipo e poi pubblicarli in un secondo momento. Tieni presente che se elimini un file, non sarà più visibile in nessuno degli oggetti a cui è allegato (Note, pagine, avatar, banner, ecc.)"
scrollToClose: "Scorri per chiudere"
advice: "Consiglio"
realtimeMode: "Modalità in tempo reale"
@@ -2464,6 +2465,8 @@ _visibility:
disableFederation: "Senza federazione"
disableFederationDescription: "Non spedire attività alle altre istanze remote"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "Alcuni file non sono stati caricati. Vuoi annullare l'operazione?"
uploaderTip: "Il file non è ancora stato caricato. Nel menu file (tre puntini), puoi ritagliare l'immagine, mettere la filigrana, decidere la presenza o l'assenza di compressione... Il file verrà caricato automaticamente quando pubblichi la Nota."
replyPlaceholder: "Rispondi a questa nota..."
quotePlaceholder: "Cita questa nota..."
channelPlaceholder: "Pubblica sul canale..."
+2
View File
@@ -3273,3 +3273,5 @@ _imageEffector:
stripe: "ストライプ"
polkadot: "ポルカドット"
checker: "チェッカー"
blockNoise: "ブロックノイズ"
tearing: "ティアリング"
+3 -1
View File
@@ -3107,7 +3107,7 @@ _uploader:
savedXPercent: "{x}% 절약"
abortConfirm: "업로드되지 않은 파일이 있습니다만, 그만 두시겠습니까?"
doneConfirm: "업로드되지 않은 파일이 있습니다만, 완료하시겠습니까?"
maxFileSizeIsX: "업드 가능한 최대 파일 크기는 {x}입니다."
maxFileSizeIsX: "업드 가능한 최대 파일 크기는 {x}입니다."
allowedTypes: "업로드 가능한 파일 유형"
tip: "파일은 아직 업로드되지 않았습니다. 이 다이얼로그에서 업로드 전의 확인, 이름 바꾸기, 압축, 자르기 등을 하실 수 있습니다. 준비가 되셨다면 '업로드' 버튼을 클릭해 업로드를 시작하실 수 있습니다."
_clientPerformanceIssueTip:
@@ -3169,3 +3169,5 @@ _imageEffector:
stripe: "줄무늬"
polkadot: "물방울 무늬"
checker: "체크 무늬"
blockNoise: "노이즈 방지"
tearing: "티어링"
+6
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "ปิดปากเซิร์ฟเวอร์นี
mediaSilenceThisInstance: "ปิดปากสื่อของเซิร์ฟเวอร์นี้"
operations: "ดำเนินการ"
software: "ซอฟต์แวร์"
softwareName: "ชื่อซอฟต์แวร์"
version: "เวอร์ชั่น"
metadata: "Metadata"
withNFiles: "{n} ไฟล์"
@@ -1293,6 +1294,10 @@ federationDisabled: "เซิร์ฟเวอร์นี้ปิดกา
reactAreYouSure: "คุณต้องการที่จะตอบสนองต่อ \" {emoji}\" หรือไม่?"
markAsSensitiveConfirm: "คุณต้องการทำเครื่องหมายสื่อนี้ว่าละเอียดอ่อนหรือไม่?"
unmarkAsSensitiveConfirm: "คุณต้องการลบการกำหนดความไวของสื่อนี้หรือไม่?"
preferences: "การตั้งค่าสภาพแวดล้อม"
preferencesProfile: "โปรไฟล์การกำหนดค่า"
preferenceSyncConflictTitle: "การตั้งค่ามีอยู่บนเซิร์ฟเวอร์"
preferenceSyncConflictText: "รายการการตั้งค่าที่เปิดใช้งานการซิงโครไนซ์จะจัดเก็บค่าไว้บนเซิร์ฟเวอร์ และพบค่าที่จัดเก็บบนเซิร์ฟเวอร์สำหรับรายการการตั้งค่านี้ คุณต้องการทำอย่างไร?"
postForm: "แบบฟอร์มการโพสต์"
information: "เกี่ยวกับ"
right: "ขวา"
@@ -1305,6 +1310,7 @@ _chat:
send: "ส่ง"
_settings:
webhook: "Webhook"
preferencesBanner: "คุณสามารถกำหนดค่าพฤติกรรมโดยรวมของไคลเอนต์ได้ตามความต้องการของคุณ"
_accountSettings:
requireSigninToViewContents: "ต้องเข้าสู่ระบบเพื่อดูเนื้อหา"
requireSigninToViewContentsDescription1: "ต้องเข้าสู่ระบบเพื่อดูบันทึกและเนื้อหาอื่น ๆ ทั้งหมดที่คุณสร้าง คาดว่าจะมีประสิทธิผลในการป้องกันไม่ให้ข้อมูลถูกเก็บรวบรวมโดยโปรแกรมรวบรวมข้อมูล"
+6
View File
@@ -220,6 +220,7 @@ silenceThisInstance: "Máy chủ im lặng"
mediaSilenceThisInstance: "Tắt nội dung đa phương tiện từ máy chủ này"
operations: "Vận hành"
software: "Phần mềm"
softwareName: "Tên phần mềm"
version: "Phiên bản"
metadata: "Metadata"
withNFiles: "{n} tập tin"
@@ -1211,6 +1212,9 @@ federationDisabled: "Liên kết bị vô hiệu hóa trên máy chủ này. B
reactAreYouSure: "Bạn có muốn phản hồi với \" {emoji} \" không?"
preferences: "Thiết lập môi trường"
accessibility: "Khả năng tiếp cận"
preferencesProfile: "Hồ sơ sở thích"
preferenceSyncConflictTitle: "Cài đặt tồn tại trên máy chủ"
preferenceSyncConflictText: "Các thiết lập đồng bộ hóa được bật sẽ lưu các giá trị của chúng vào máy chủ. Tuy nhiên, có những giá trị hiện có trên máy chủ. Bạn muốn ghi đè lên bộ giá trị nào?"
paste: "dán"
postForm: "Mẫu đăng"
information: "Giới thiệu"
@@ -1223,6 +1227,8 @@ _chat:
members: "Thành viên"
home: "Trang chính"
send: "Gửi"
_settings:
preferencesBanner: "Bạn có thể cấu hình hành vi chung của máy khách theo sở thích của mình."
_accountSettings:
requireSigninToViewContents: "Yêu cầu đăng nhập để xem nội dung"
requireSigninToViewContentsDescription1: "Yêu cầu đăng nhập để xem tất cả ghi chú và nội dung khác mà bạn tạo. Điều này được kỳ vọng sẽ có hiệu quả trong việc ngăn chặn thông tin bị thu thập bởi các trình thu thập thông tin."
+5 -3
View File
@@ -1631,7 +1631,7 @@ _serverSettings:
inquiryUrl: "联络地址"
inquiryUrlDescription: "用来指定诸如向服务运营商咨询的论坛地址,或记载了运营商联系方式之类的网页地址。"
openRegistration: "开放注册"
openRegistrationWarning: "开放注册有风险。建议仅当能够持续监控服务器并在出现问题时能够立即响应时才打开它。"
openRegistrationWarning: "开放注册有风险。建议仅当能够持续监控服务器并在出现问题时能够立即响应时才打开它。"
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "若在一段时间内没有检测到管理活动,为防止垃圾信息,此设定将自动关闭。"
deliverSuspendedSoftware: "停止投递的软件"
deliverSuspendedSoftwareDescription: "可因安全漏洞之类的原因,停止向指定的服务器及服务器版本送信。版本信息由服务器提供,不保证可靠性。可使用 semver 范围来指定版本,但指定 >= 2024.3.1 将不包括如 2024.3.1-custom.0 等自定义版本,因此建议像 >= 2024.3.1-0 这样指定 prerelease 版本。"
@@ -2143,7 +2143,7 @@ _wordMute:
muteWordsDescription: "AND 条件用空格分隔,OR 条件用换行符分隔。"
muteWordsDescription2: "正则表达式用斜线包裹"
_instanceMute:
instanceMuteDescription: "隐藏服务器中所有帖子和转帖,包括这些服务器上用户回复。"
instanceMuteDescription: "隐藏服务器中所有帖子和转帖,包括这些服务器上用户回复。"
instanceMuteDescription2: "一行一个"
title: "下面实例中的帖子将被隐藏。"
heading: "已隐藏的服务器"
@@ -2493,7 +2493,7 @@ _profile:
avatarDecorationMax: "最多可添加 {max} 个挂件"
followedMessage: "被关注时显示的消息"
followedMessageDescription: "可以设置被关注时向对方显示的短消息。"
followedMessageDescriptionForLockedAccount: "需要批准才能关注的情况下,消息在请求被批准后显示。"
followedMessageDescriptionForLockedAccount: "需要批准才能关注的情况下,消息在请求被批准后显示。"
_exportOrImport:
allNotes: "所有帖子"
favoritedNotes: "收藏的帖子"
@@ -3169,3 +3169,5 @@ _imageEffector:
stripe: "条纹"
polkadot: "波点"
checker: "检查"
blockNoise: "块状噪点"
tearing: "撕裂"
+2
View File
@@ -3169,3 +3169,5 @@ _imageEffector:
stripe: "條紋"
polkadot: "波卡圓點"
checker: "棋盤格"
blockNoise: "阻擋雜訊"
tearing: "撕裂"
+13 -13
View File
@@ -1,12 +1,12 @@
{
"name": "misskey",
"version": "2025.6.1-beta.1",
"version": "2025.6.2",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/misskey-dev/misskey.git"
},
"packageManager": "pnpm@10.11.0",
"packageManager": "pnpm@10.12.1",
"workspaces": [
"packages/frontend-shared",
"packages/frontend",
@@ -53,28 +53,28 @@
},
"dependencies": {
"cssnano": "7.0.7",
"esbuild": "0.25.4",
"execa": "9.5.3",
"esbuild": "0.25.5",
"execa": "9.6.0",
"fast-glob": "3.3.3",
"glob": "11.0.2",
"ignore-walk": "7.0.0",
"js-yaml": "4.1.0",
"postcss": "8.5.3",
"postcss": "8.5.4",
"tar": "7.4.3",
"terser": "5.39.2",
"terser": "5.42.0",
"typescript": "5.8.3"
},
"devDependencies": {
"@misskey-dev/eslint-plugin": "2.1.0",
"@types/node": "22.15.21",
"@typescript-eslint/eslint-plugin": "8.32.1",
"@typescript-eslint/parser": "8.32.1",
"@types/node": "22.15.31",
"@typescript-eslint/eslint-plugin": "8.34.0",
"@typescript-eslint/parser": "8.34.0",
"cross-env": "7.0.3",
"cypress": "14.4.0",
"eslint": "9.27.0",
"globals": "16.1.0",
"cypress": "14.4.1",
"eslint": "9.28.0",
"globals": "16.2.0",
"ncp": "2.0.0",
"pnpm": "10.11.0",
"pnpm": "10.12.1",
"start-server-and-test": "2.0.12"
},
"optionalDependencies": {
+5 -1
View File
@@ -39,7 +39,11 @@ export class I18n<T extends ILocale> {
private devMode: boolean;
constructor(public locale: T, devMode = false) {
this.devMode = devMode;
// 場合によってはバージョンアップ前の翻訳データを参照した結果存在しないプロパティにアクセスしてクライアントが起動できなくなることがある問題の応急処置として非devモードでもプロキシする
// TODO: https://github.com/misskey-dev/misskey/issues/14453 が実装されたらそのようなことは発生し得なくなるため消す
const oukyuusyoti = true;
this.devMode = devMode || oukyuusyoti;
//#region BIND
this.t = this.t.bind(this);
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
v-if="v.type === 'boolean'"
v-model="layer.params[k]"
>
<template #label>{{ k }}</template>
<template #label>{{ fx.params[k].label ?? k }}</template>
</MkSwitch>
<MkRange
v-else-if="v.type === 'number'"
@@ -29,6 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:min="v.min"
:max="v.max"
:step="v.step"
:textConverter="fx.params[k].toViewValue"
@thumbDoubleClicked="() => {
if (fx.params[k].default != null) {
layer.params[k] = fx.params[k].default;
@@ -37,13 +38,13 @@ SPDX-License-Identifier: AGPL-3.0-only
}
}"
>
<template #label>{{ k }}</template>
<template #label>{{ fx.params[k].label ?? k }}</template>
</MkRange>
<MkRadios
v-else-if="v.type === 'number:enum'"
v-model="layer.params[k]"
>
<template #label>{{ k }}</template>
<template #label>{{ fx.params[k].label ?? k }}</template>
<option v-for="item in v.enum" :value="item.value">{{ item.label }}</option>
</MkRadios>
<div v-else-if="v.type === 'seed'">
@@ -55,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:max="10000"
:step="1"
>
<template #label>{{ k }}</template>
<template #label>{{ fx.params[k].label ?? k }}</template>
</MkRange>
</div>
<MkInput
@@ -64,7 +65,7 @@ SPDX-License-Identifier: AGPL-3.0-only
type="color"
@update:modelValue="v => { const c = getRgb(v); if (c != null) layer.params[k] = c; }"
>
<template #label>{{ k }}</template>
<template #label>{{ fx.params[k].label ?? k }}</template>
</MkInput>
</div>
</div>
@@ -96,7 +96,7 @@ watch(layers, async () => {
}, { deep: true });
function addEffect(ev: MouseEvent) {
os.popupMenu(FXS.filter(fx => fx.id !== 'watermarkPlacement').map((fx) => ({
os.popupMenu(FXS.map((fx) => ({
text: fx.name,
action: () => {
layers.push({
+16 -8
View File
@@ -321,20 +321,27 @@ const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
url: `https://${host}/notes/${appearNote.id}`,
}));
/* Overload FunctionLint
/* eslint-disable no-redeclare */
/** checkOnlyでは純粋なワードミュート結果をbooleanで返却する */
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: true): boolean;
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: false): Array<string | string[]> | false | 'sensitiveMute';
*/
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly = false): Array<string | string[]> | false | 'sensitiveMute' {
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly?: false): Array<string | string[]> | false | 'sensitiveMute';
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly = false): Array<string | string[]> | boolean | 'sensitiveMute' {
if (mutedWords != null) {
const result = checkWordMute(noteToCheck, $i, mutedWords);
if (Array.isArray(result)) return result;
if (Array.isArray(result)) {
return checkOnly ? (result.length > 0) : result;
}
const replyResult = noteToCheck.reply && checkWordMute(noteToCheck.reply, $i, mutedWords);
if (Array.isArray(replyResult)) return replyResult;
if (Array.isArray(replyResult)) {
return checkOnly ? (replyResult.length > 0) : replyResult;
}
const renoteResult = noteToCheck.renote && checkWordMute(noteToCheck.renote, $i, mutedWords);
if (Array.isArray(renoteResult)) return renoteResult;
if (Array.isArray(renoteResult)) {
return checkOnly ? (renoteResult.length > 0) : renoteResult;
}
}
if (checkOnly) return false;
@@ -345,6 +352,7 @@ function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string
return false;
}
/* eslint-enable no-redeclare */
const keymap = {
'r': () => {
@@ -417,7 +425,7 @@ if (!props.mock) {
const users = renotes.map(x => x.user);
if (users.length < 1) return;
if (users.length < 1 || renoteButton.value == null) return;
const { dispose } = os.popup(MkUsersTooltip, {
showing,
@@ -62,6 +62,7 @@ import { useInterval } from '@@/js/use-interval.js';
import { getScrollContainer, scrollToTop } from '@@/js/scroll.js';
import type { BasicTimelineType } from '@/timelines.js';
import type { PagingCtx } from '@/composables/use-pagination.js';
import type { SoundStore } from '@/preferences/def.js';
import { usePagination } from '@/composables/use-pagination.js';
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
import { useStream } from '@/stream.js';
@@ -83,6 +84,7 @@ const props = withDefaults(defineProps<{
channel?: string;
role?: string;
sound?: boolean;
customSound?: SoundStore | null;
withRenotes?: boolean;
withReplies?: boolean;
withSensitive?: boolean;
@@ -92,6 +94,8 @@ const props = withDefaults(defineProps<{
withReplies: false,
withSensitive: true,
onlyFiles: false,
sound: false,
customSound: null,
});
provide('inTimeline', true);
@@ -190,7 +194,11 @@ function prepend(note: Misskey.entities.Note) {
}
if (props.sound) {
sound.playMisskeySfx($i && (note.userId === $i.id) ? 'noteMy' : 'note');
if (props.customSound) {
sound.playMisskeySfxFile(props.customSound);
} else {
sound.playMisskeySfx($i && (note.userId === $i.id) ? 'noteMy' : 'note');
}
}
}
@@ -420,7 +428,7 @@ defineExpose({
background: var(--MI_THEME-panel);
}
.note {
.note:not(:empty) {
border-bottom: solid 0.5px var(--MI_THEME-divider);
}
@@ -24,8 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkMediaList :mediaList="note.files.slice(0, 4)"/>
</div>
<div v-if="note.reactionCount > 0" :class="$style.reactions">
<!-- TODO -->
<!--<MkReactionsViewer :note="note" :maxNumber="16"/>-->
<MkReactionsViewer :noteId="note.id" :reactions="note.reactions" :reactionEmojis="note.reactionEmojis" :myReaction="note.myReaction" :maxNumber="16"/>
</div>
</div>
</div>
@@ -26,6 +26,8 @@ SPDX-License-Identifier: AGPL-3.0-only
:withReplies="withReplies"
:withSensitive="withSensitive"
:onlyFiles="onlyFiles"
:sound="true"
:customSound="soundSetting"
/>
</XColumn>
</template>
@@ -542,7 +542,7 @@ function smallerVisibility(a: Visibility, b: Visibility): Visibility {
export function getRenoteMenu(props: {
note: Misskey.entities.Note;
renoteButton: ShallowRef<HTMLElement | undefined>;
renoteButton: ShallowRef<HTMLElement | null | undefined>;
mock?: boolean;
}) {
const appearNote = getAppearNote(props.note);
@@ -19,6 +19,8 @@ type ParamTypeToPrimitive = {
type ImageEffectorFxParamDefs = Record<string, {
type: keyof ParamTypeToPrimitive;
default: any;
label?: string;
toViewValue?: (v: any) => string;
}>;
export function defineImageEffectorFx<ID extends string, PS extends ImageEffectorFxParamDefs, US extends string[]>(fx: ImageEffectorFx<ID, PS, US>) {
@@ -10,20 +10,17 @@ import { FX_colorClamp } from './fxs/colorClamp.js';
import { FX_colorClampAdvanced } from './fxs/colorClampAdvanced.js';
import { FX_distort } from './fxs/distort.js';
import { FX_polkadot } from './fxs/polkadot.js';
import { FX_glitch } from './fxs/glitch.js';
import { FX_tearing } from './fxs/tearing.js';
import { FX_grayscale } from './fxs/grayscale.js';
import { FX_invert } from './fxs/invert.js';
import { FX_mirror } from './fxs/mirror.js';
import { FX_stripe } from './fxs/stripe.js';
import { FX_threshold } from './fxs/threshold.js';
import { FX_watermarkPlacement } from './fxs/watermarkPlacement.js';
import { FX_zoomLines } from './fxs/zoomLines.js';
import { FX_blockNoise } from './fxs/blockNoise.js';
import type { ImageEffectorFx } from './ImageEffector.js';
export const FXS = [
FX_watermarkPlacement,
FX_chromaticAberration,
FX_glitch,
FX_mirror,
FX_invert,
FX_grayscale,
@@ -36,4 +33,7 @@ export const FXS = [
FX_stripe,
FX_polkadot,
FX_checker,
FX_chromaticAberration,
FX_tearing,
FX_blockNoise,
] as const satisfies ImageEffectorFx<string, any>[];
@@ -0,0 +1,119 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import seedrandom from 'seedrandom';
import { defineImageEffectorFx } from '../ImageEffector.js';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform int u_amount;
uniform float u_shiftStrengths[128];
uniform vec2 u_shiftOrigins[128];
uniform vec2 u_shiftSizes[128];
uniform float u_channelShift;
out vec4 out_color;
void main() {
// TODO: ピクセル毎に計算する必要はないのでuniformにする
float aspect_ratio = min(in_resolution.x, in_resolution.y) / max(in_resolution.x, in_resolution.y);
float aspect_ratio_x = in_resolution.x > in_resolution.y ? 1.0 : aspect_ratio;
float aspect_ratio_y = in_resolution.x < in_resolution.y ? 1.0 : aspect_ratio;
float v = 0.0;
for (int i = 0; i < u_amount; i++) {
if (
in_uv.x * aspect_ratio_x > ((u_shiftOrigins[i].x * aspect_ratio_x) - u_shiftSizes[i].x) &&
in_uv.x * aspect_ratio_x < ((u_shiftOrigins[i].x * aspect_ratio_x) + u_shiftSizes[i].x) &&
in_uv.y * aspect_ratio_y > ((u_shiftOrigins[i].y * aspect_ratio_y) - u_shiftSizes[i].y) &&
in_uv.y * aspect_ratio_y < ((u_shiftOrigins[i].y * aspect_ratio_y) + u_shiftSizes[i].y)
) {
v += u_shiftStrengths[i];
}
}
float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r;
float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g;
float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b;
float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a;
out_color = vec4(r, g, b, a);
}
`;
export const FX_blockNoise = defineImageEffectorFx({
id: 'blockNoise' as const,
name: i18n.ts._imageEffector._fxs.glitch + ': ' + i18n.ts._imageEffector._fxs.blockNoise,
shader,
uniforms: ['amount', 'channelShift'] as const,
params: {
amount: {
type: 'number' as const,
default: 50,
min: 1,
max: 100,
step: 1,
},
strength: {
type: 'number' as const,
default: 0.05,
min: -1,
max: 1,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
width: {
type: 'number' as const,
default: 0.05,
min: 0.01,
max: 1,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
height: {
type: 'number' as const,
default: 0.01,
min: 0.01,
max: 1,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
channelShift: {
type: 'number' as const,
default: 0,
min: 0,
max: 10,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
seed: {
type: 'seed' as const,
default: 100,
},
},
main: ({ gl, program, u, params }) => {
gl.uniform1i(u.amount, params.amount);
gl.uniform1f(u.channelShift, params.channelShift);
const margin = 0;
const rnd = seedrandom(params.seed.toString());
for (let i = 0; i < params.amount; i++) {
const o = gl.getUniformLocation(program, `u_shiftOrigins[${i.toString()}]`);
gl.uniform2f(o, (rnd() * (1 + (margin * 2))) - margin, (rnd() * (1 + (margin * 2))) - margin);
const s = gl.getUniformLocation(program, `u_shiftStrengths[${i.toString()}]`);
gl.uniform1f(s, (1 - (rnd() * 2)) * params.strength);
const sizes = gl.getUniformLocation(program, `u_shiftSizes[${i.toString()}]`);
gl.uniform2f(sizes, params.width, params.height);
}
},
});
@@ -58,6 +58,7 @@ export const FX_checker = defineImageEffectorFx({
min: -1.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 90) + '°',
},
scale: {
type: 'number' as const,
@@ -76,6 +77,7 @@ export const FX_checker = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
},
main: ({ gl, u, params }) => {
@@ -72,7 +72,7 @@ void main() {
vec3 color = in_color.rgb;
color = color * u_brightness;
color += vec3(clamp(u_lightness, 0.0, 2.0) - 1.0);
color += vec3(u_lightness);
color = (color - 0.5) * u_contrast + 0.5;
vec3 hsl = rgb2hsl(color);
@@ -92,45 +92,50 @@ export const FX_colorAdjust = defineImageEffectorFx({
params: {
lightness: {
type: 'number' as const,
default: 100,
min: 0,
max: 200,
step: 1,
default: 0,
min: -1,
max: 1,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
contrast: {
type: 'number' as const,
default: 100,
default: 1,
min: 0,
max: 200,
step: 1,
max: 4,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
hue: {
type: 'number' as const,
default: 0,
min: -360,
max: 360,
step: 1,
min: -1,
max: 1,
step: 0.01,
toViewValue: v => Math.round(v * 180) + '°',
},
brightness: {
type: 'number' as const,
default: 100,
default: 1,
min: 0,
max: 200,
step: 1,
max: 4,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
saturation: {
type: 'number' as const,
default: 100,
default: 1,
min: 0,
max: 200,
step: 1,
max: 4,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
},
main: ({ gl, u, params }) => {
gl.uniform1f(u.brightness, params.brightness / 100);
gl.uniform1f(u.contrast, params.contrast / 100);
gl.uniform1f(u.hue, params.hue / 360);
gl.uniform1f(u.lightness, params.lightness / 100);
gl.uniform1f(u.saturation, params.saturation / 100);
gl.uniform1f(u.brightness, params.brightness);
gl.uniform1f(u.contrast, params.contrast);
gl.uniform1f(u.hue, params.hue / 2);
gl.uniform1f(u.lightness, params.lightness);
gl.uniform1f(u.saturation, params.saturation);
},
});
@@ -37,6 +37,7 @@ export const FX_colorClamp = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
min: {
type: 'number' as const,
@@ -44,6 +45,7 @@ export const FX_colorClamp = defineImageEffectorFx({
min: -1.0,
max: 0.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
},
main: ({ gl, u, params }) => {
@@ -41,6 +41,7 @@ export const FX_colorClampAdvanced = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
rMin: {
type: 'number' as const,
@@ -48,6 +49,7 @@ export const FX_colorClampAdvanced = defineImageEffectorFx({
min: -1.0,
max: 0.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
gMax: {
type: 'number' as const,
@@ -55,6 +57,7 @@ export const FX_colorClampAdvanced = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
gMin: {
type: 'number' as const,
@@ -62,6 +65,7 @@ export const FX_colorClampAdvanced = defineImageEffectorFx({
min: -1.0,
max: 0.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
bMax: {
type: 'number' as const,
@@ -69,6 +73,7 @@ export const FX_colorClampAdvanced = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
bMin: {
type: 'number' as const,
@@ -76,6 +81,7 @@ export const FX_colorClampAdvanced = defineImageEffectorFx({
min: -1.0,
max: 0.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
},
main: ({ gl, u, params }) => {
@@ -9,6 +9,10 @@ import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
@@ -20,8 +24,8 @@ out vec4 out_color;
void main() {
float v = u_direction == 0 ?
sin(u_phase + in_uv.y * u_frequency) * u_strength :
sin(u_phase + in_uv.x * u_frequency) * u_strength;
sin((HALF_PI + (u_phase * PI) - (u_frequency / 2.0)) + in_uv.y * u_frequency) * u_strength :
sin((HALF_PI + (u_phase * PI) - (u_frequency / 2.0)) + in_uv.x * u_frequency) * u_strength;
vec4 in_color = u_direction == 0 ?
texture(in_texture, vec2(in_uv.x + v, in_uv.y)) :
texture(in_texture, vec2(in_uv.x, in_uv.y + v));
@@ -38,32 +42,34 @@ export const FX_distort = defineImageEffectorFx({
direction: {
type: 'number:enum' as const,
enum: [{ value: 0, label: 'v' }, { value: 1, label: 'h' }],
default: 0,
default: 1,
},
phase: {
type: 'number' as const,
default: 50.0,
min: 0.0,
max: 100,
default: 0.0,
min: -1.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
frequency: {
type: 'number' as const,
default: 50,
default: 30,
min: 0,
max: 100,
step: 0.1,
},
strength: {
type: 'number' as const,
default: 0.1,
default: 0.05,
min: 0,
max: 1,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
},
main: ({ gl, u, params }) => {
gl.uniform1f(u.phase, params.phase / 10);
gl.uniform1f(u.phase, params.phase);
gl.uniform1f(u.frequency, params.frequency);
gl.uniform1f(u.strength, params.strength);
gl.uniform1i(u.direction, params.direction);
@@ -90,6 +90,7 @@ export const FX_polkadot = defineImageEffectorFx({
min: -1.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 90) + '°',
},
scale: {
type: 'number' as const,
@@ -111,6 +112,7 @@ export const FX_polkadot = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
minorDivisions: {
type: 'number' as const,
@@ -132,6 +134,7 @@ export const FX_polkadot = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
color: {
type: 'color' as const,
@@ -60,6 +60,7 @@ export const FX_stripe = defineImageEffectorFx({
min: -1.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 90) + '°',
},
frequency: {
type: 'number' as const,
@@ -74,6 +75,7 @@ export const FX_stripe = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
color: {
type: 'color' as const,
@@ -85,6 +87,7 @@ export const FX_stripe = defineImageEffectorFx({
min: 0.0,
max: 1.0,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
},
main: ({ gl, u, params }) => {
@@ -37,9 +37,9 @@ void main() {
}
`;
export const FX_glitch = defineImageEffectorFx({
id: 'glitch' as const,
name: i18n.ts._imageEffector._fxs.glitch,
export const FX_tearing = defineImageEffectorFx({
id: 'tearing' as const,
name: i18n.ts._imageEffector._fxs.glitch + ': ' + i18n.ts._imageEffector._fxs.tearing,
shader,
uniforms: ['amount', 'channelShift'] as const,
params: {
@@ -52,17 +52,19 @@ export const FX_glitch = defineImageEffectorFx({
},
strength: {
type: 'number' as const,
default: 5,
min: -100,
max: 100,
default: 0.05,
min: -1,
max: 1,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
size: {
type: 'number' as const,
default: 20,
default: 0.2,
min: 0,
max: 100,
max: 1,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
channelShift: {
type: 'number' as const,
@@ -70,6 +72,7 @@ export const FX_glitch = defineImageEffectorFx({
min: 0,
max: 10,
step: 0.01,
toViewValue: v => Math.round(v * 100) + '%',
},
seed: {
type: 'seed' as const,
@@ -87,10 +90,10 @@ export const FX_glitch = defineImageEffectorFx({
gl.uniform1f(o, rnd());
const s = gl.getUniformLocation(program, `u_shiftStrengths[${i.toString()}]`);
gl.uniform1f(s, (1 - (rnd() * 2)) * (params.strength / 100));
gl.uniform1f(s, (1 - (rnd() * 2)) * params.strength);
const h = gl.getUniformLocation(program, `u_shiftHeights[${i.toString()}]`);
gl.uniform1f(h, rnd() * (params.size / 100));
gl.uniform1f(h, rnd() * params.size);
}
},
});
+1 -1
View File
@@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
"version": "2025.6.1-beta.1",
"version": "2025.6.2",
"description": "Misskey SDK for JavaScript",
"license": "MIT",
"main": "./built/index.js",
+1 -1
View File
@@ -106,7 +106,7 @@ export class APIClient {
this.fetch(`${this.origin}/api/${endpoint}`, {
method: 'POST',
body: payload,
headers: {
headers: mediaType === 'multipart/form-data' ? {} : {
'Content-Type': mediaType,
},
credentials: 'omit',
+2 -6
View File
@@ -94,11 +94,7 @@ describe('API', () => {
fetchMock.resetMocks();
fetchMock.mockResponse(async (req) => {
if (req.method == 'POST' && req.url == 'https://misskey.test/api/drive/files/create') {
if (req.headers.get('Content-Type')?.includes('multipart/form-data')) {
return JSON.stringify({ id: 'foo' });
} else {
return { status: 400 };
}
return JSON.stringify({ id: 'foo' });
} else {
return { status: 404 };
}
@@ -123,7 +119,7 @@ describe('API', () => {
expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({
url: 'https://misskey.test/api/drive/files/create',
method: 'POST',
contentType: 'multipart/form-data',
contentType: undefined,
body: {
i: 'TOKEN',
file: testFile,
+261 -490
View File
File diff suppressed because it is too large Load Diff