Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 978ae706eb | |||
| 824643a44e | |||
| 213c569242 | |||
| a1cf2d3074 | |||
| 4ea7c76c02 | |||
| 1782a353d3 | |||
| c69a13b592 | |||
| 40e35c051a | |||
| b93717be33 | |||
| fe805fb7f0 | |||
| e9af9d4451 | |||
| ce90fee586 | |||
| 5bec8ba6b0 | |||
| 3dbfd80d65 | |||
| b33eeb1366 | |||
| 420756d744 | |||
| 32d721abf1 | |||
| 8ea6aa2ef3 | |||
| bc07b79a23 | |||
| aae7961540 | |||
| 1ad32990cb | |||
| 89db7b3fa8 | |||
| 151121a567 | |||
| 966e0812f5 | |||
| d378156212 | |||
| 568021498f |
+13
-5
@@ -1,13 +1,18 @@
|
||||
## 2025.6.2
|
||||
|
||||
### Client
|
||||
- Fix: キャッシュを削除しないとクライアントが使用できないことがある問題を修正
|
||||
- 翻訳の更新
|
||||
|
||||
## 2025.6.1
|
||||
|
||||
### Note
|
||||
- Misskey Webプラグインのnote_view_interruptorは不具合の影響により現在一時的に無効化されています。
|
||||
|
||||
### General
|
||||
-
|
||||
- AiScript Misskey拡張API(Misskey 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
|
||||
|
||||
|
||||
@@ -3169,3 +3169,5 @@ _imageEffector:
|
||||
stripe: "Bandes"
|
||||
polkadot: "Lunars"
|
||||
checker: "Escacs"
|
||||
blockNoise: "Bloqueig de soroll"
|
||||
tearing: "Trencament d'imatge "
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -3169,3 +3169,5 @@ _imageEffector:
|
||||
stripe: "Rayas"
|
||||
polkadot: "Lunares"
|
||||
checker: "Corrector"
|
||||
blockNoise: "Bloquear Ruido"
|
||||
tearing: "Rasgado de Imagen (Tearing)"
|
||||
|
||||
Vendored
+8
@@ -12220,6 +12220,14 @@ export interface Locale extends ILocale {
|
||||
* チェッカー
|
||||
*/
|
||||
"checker": string;
|
||||
/**
|
||||
* ブロックノイズ
|
||||
*/
|
||||
"blockNoise": string;
|
||||
/**
|
||||
* ティアリング
|
||||
*/
|
||||
"tearing": string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
+5
-2
@@ -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..."
|
||||
|
||||
@@ -3273,3 +3273,5 @@ _imageEffector:
|
||||
stripe: "ストライプ"
|
||||
polkadot: "ポルカドット"
|
||||
checker: "チェッカー"
|
||||
blockNoise: "ブロックノイズ"
|
||||
tearing: "ティアリング"
|
||||
|
||||
+3
-1
@@ -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: "티어링"
|
||||
|
||||
@@ -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: "ต้องเข้าสู่ระบบเพื่อดูบันทึกและเนื้อหาอื่น ๆ ทั้งหมดที่คุณสร้าง คาดว่าจะมีประสิทธิผลในการป้องกันไม่ให้ข้อมูลถูกเก็บรวบรวมโดยโปรแกรมรวบรวมข้อมูล"
|
||||
|
||||
@@ -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
@@ -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: "撕裂"
|
||||
|
||||
@@ -3169,3 +3169,5 @@ _imageEffector:
|
||||
stripe: "條紋"
|
||||
polkadot: "波卡圓點"
|
||||
checker: "棋盤格"
|
||||
blockNoise: "阻擋雜訊"
|
||||
tearing: "撕裂"
|
||||
|
||||
+13
-13
@@ -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": {
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -321,20 +321,27 @@ const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
|
||||
url: `https://${host}/notes/${appearNote.id}`,
|
||||
}));
|
||||
|
||||
/* Overload FunctionにLintが対応していないのでコメントアウト
|
||||
/* 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 }) => {
|
||||
|
||||
+13
-10
@@ -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,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",
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
|
||||
Generated
+261
-490
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user