Merge branch 'misskey-dev:develop' into develop

This commit is contained in:
老兄 2023-07-20 00:32:47 +08:00 committed by GitHub
commit 7fb0e8c8a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1589 additions and 2316 deletions

View File

@ -36,9 +36,12 @@
- フォローやお気に入り登録をしていないチャンネルを開く時は概要ページを開くように - フォローやお気に入り登録をしていないチャンネルを開く時は概要ページを開くように
- 画面ビューワをタップした場合、マウスクリックと同様に画像ビューワを閉じるように - 画面ビューワをタップした場合、マウスクリックと同様に画像ビューワを閉じるように
- オフライン時の画面にリロードボタンを追加 - オフライン時の画面にリロードボタンを追加
- Renote時に公開範囲のデフォルト設定が適用されるように
- Deckで非ルートページにアクセスした際に簡易UIで表示しない設定を追加 - Deckで非ルートページにアクセスした際に簡易UIで表示しない設定を追加
- ロール設定画面でロールIDを確認できるように - ロール設定画面でロールIDを確認できるように
- コンテキストメニュー表示時のパフォーマンスを改善 - コンテキストメニュー表示時のパフォーマンスを改善
- フォロー/フォロワー非公開時の表示を改善
- AiScriptを0.14.0に更新
- Fix: サーバーメトリクスが90度傾いている - Fix: サーバーメトリクスが90度傾いている
- Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正 - Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正
- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正 - Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正
@ -59,9 +62,11 @@
- MeilisearchにIndexするートの範囲を設定できるように - MeilisearchにIndexするートの範囲を設定できるように
- Export notes with file detail - Export notes with file detail
- Add unix socket support - Add unix socket support
- Fix: リモートサーバーに無意味なActivityPubの配信を行うことがあるのを修正
- Fix: Remove Meilisearch index when notes are deleted - Fix: Remove Meilisearch index when notes are deleted
- Fix: 非英語環境でのPostgreSQLのエラーハンドリングを修正 - Fix: 非英語環境でのPostgreSQLのエラーハンドリングを修正
- Fix: インスタンスのアイコンがbase64の場合の挙動を修正 - Fix: インスタンスのアイコンがbase64の場合の挙動を修正
- Fix: ローカルの `Person` を指す `acct` URI を解析するときのバグを修正しました
## 13.13.2 ## 13.13.2

View File

@ -1996,6 +1996,7 @@ _deck:
introduction: "Erstelle eine auf dich zugeschneiderte Benutzeroberfläche durch das Aneinanderreihen von Spalten!" introduction: "Erstelle eine auf dich zugeschneiderte Benutzeroberfläche durch das Aneinanderreihen von Spalten!"
introduction2: "Klicke auf das + rechts um wann immer du möchtest neue Spalten hinzuzufügen." introduction2: "Klicke auf das + rechts um wann immer du möchtest neue Spalten hinzuzufügen."
widgetsIntroduction: "Drücke bitte \"Widgets bearbeiten\" im Spaltenmenü und füge ein Widget hinzu." widgetsIntroduction: "Drücke bitte \"Widgets bearbeiten\" im Spaltenmenü und füge ein Widget hinzu."
useSimpleUiForNonRootPages: "Simple Benutzeroberfläche für navigierte Seiten verwenden"
_columns: _columns:
main: "Hauptspalte" main: "Hauptspalte"
widgets: "Widgets" widgets: "Widgets"

View File

@ -1996,6 +1996,7 @@ _deck:
introduction: "Create the perfect interface for you by arranging columns freely!" introduction: "Create the perfect interface for you by arranging columns freely!"
introduction2: "Click on the + on the right of the screen to add new colums whenever you want." introduction2: "Click on the + on the right of the screen to add new colums whenever you want."
widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget." widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget."
useSimpleUiForNonRootPages: "Use simple UI for navigated pages"
_columns: _columns:
main: "Main" main: "Main"
widgets: "Widgets" widgets: "Widgets"

View File

@ -779,10 +779,10 @@ info: "Informazioni"
userInfo: "Informazioni utente" userInfo: "Informazioni utente"
unknown: "Sconosciuto" unknown: "Sconosciuto"
onlineStatus: "Stato di connessione" onlineStatus: "Stato di connessione"
hideOnlineStatus: "Stato invisibile" hideOnlineStatus: "Modalità invisibile"
hideOnlineStatusDescription: "Abilitare l'opzione di stato invisibile può guastare la praticità di singole funzioni, come la ricerca." hideOnlineStatusDescription: "Attivando questa opzione potresti ridurre l'usabilità di alcune funzioni, come la ricerca."
online: "Online" online: "Online"
active: "Attiv@" active: "Attività"
offline: "Offline" offline: "Offline"
notRecommended: "Sconsigliato" notRecommended: "Sconsigliato"
botProtection: "Protezione contro i bot" botProtection: "Protezione contro i bot"
@ -856,8 +856,8 @@ makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a di
classic: "Classico" classic: "Classico"
muteThread: "Silenzia la conversazione" muteThread: "Silenzia la conversazione"
unmuteThread: "Riattiva la conversazione" unmuteThread: "Riattiva la conversazione"
ffVisibility: "Ambito pubblico del collegamento" ffVisibility: "Visibilità delle connessioni"
ffVisibilityDescription: "È possibile impostare la portata pubblica delle informazioni sui propri follower/seguaci." ffVisibilityDescription: "Puoi scegliere a chi mostrare le tue relazioni con altri profili nel fediverso."
continueThread: "Altri thread." continueThread: "Altri thread."
deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?" deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?"
incorrectPassword: "La password è errata." incorrectPassword: "La password è errata."
@ -1996,6 +1996,7 @@ _deck:
introduction: "Combinate le colonne per creare la vostra interfaccia!" introduction: "Combinate le colonne per creare la vostra interfaccia!"
introduction2: "È possibile aggiungere colonne in qualsiasi momento premendo + sulla destra dello schermo." introduction2: "È possibile aggiungere colonne in qualsiasi momento premendo + sulla destra dello schermo."
widgetsIntroduction: "Dal menu della colonna, selezionare \"Modifica i riquadri\" per aggiungere un un riquadro con funzionalità" widgetsIntroduction: "Dal menu della colonna, selezionare \"Modifica i riquadri\" per aggiungere un un riquadro con funzionalità"
useSimpleUiForNonRootPages: "Visualizza sotto pagine con interfaccia web semplice"
_columns: _columns:
main: "Principale" main: "Principale"
widgets: "Riquadri" widgets: "Riquadri"

View File

@ -49,11 +49,15 @@ delete: "삭제"
deleteAndEdit: "삭제 후 편집" deleteAndEdit: "삭제 후 편집"
deleteAndEditConfirm: "이 노트를 삭제한 뒤 다시 편집하시겠습니까? 이 노트에 대한 리액션, 리노트, 답글 또한 모두 삭제됩니다." deleteAndEditConfirm: "이 노트를 삭제한 뒤 다시 편집하시겠습니까? 이 노트에 대한 리액션, 리노트, 답글 또한 모두 삭제됩니다."
addToList: "리스트에 추가" addToList: "리스트에 추가"
addToAntenna: "안테나에 추가"
sendMessage: "메시지 보내기" sendMessage: "메시지 보내기"
copyRSS: "RSS 복사" copyRSS: "RSS 복사"
copyUsername: "유저명 복사" copyUsername: "유저명 복사"
copyUserId: "유저 ID 복사" copyUserId: "유저 ID 복사"
copyNoteId: "노트 ID 복사" copyNoteId: "노트 ID 복사"
copyFileId: "파일 ID 복사"
copyFolderId: "폴더 ID 복사"
copyProfileUrl: "프로필 URL 복사"
searchUser: "사용자 검색" searchUser: "사용자 검색"
reply: "답글" reply: "답글"
loadMore: "더 보기" loadMore: "더 보기"
@ -152,6 +156,8 @@ addEmoji: "이모지 추가"
settingGuide: "추천 설정" settingGuide: "추천 설정"
cacheRemoteFiles: "리모트 파일을 캐시" cacheRemoteFiles: "리모트 파일을 캐시"
cacheRemoteFilesDescription: "이 설정을 해지하면 리모트 파일을 캐시하지 않고 해당 파일을 직접 링크하게 됩니다. 그에 따라 서버의 저장 공간을 절약할 수 있지만, 썸네일이 생성되지 않기 때문에 통신량이 증가합니다." cacheRemoteFilesDescription: "이 설정을 해지하면 리모트 파일을 캐시하지 않고 해당 파일을 직접 링크하게 됩니다. 그에 따라 서버의 저장 공간을 절약할 수 있지만, 썸네일이 생성되지 않기 때문에 통신량이 증가합니다."
cacheRemoteSensitiveFiles: "리모트의 민감한 파일을 캐시"
cacheRemoteSensitiveFilesDescription: "이 설정을 비활성화하면 리모트의 민감한 파일은 캐시하지 않고 리모트에서 직접 가져오도록 합니다."
flagAsBot: "나는 봇입니다" flagAsBot: "나는 봇입니다"
flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우에 활성화해 주세요. 이 플래그를 활성화하면, 다른 봇이 이를 참고하여 봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 Bot 운영에 최적화되는 등의 변화가 생깁니다." flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우에 활성화해 주세요. 이 플래그를 활성화하면, 다른 봇이 이를 참고하여 봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 Bot 운영에 최적화되는 등의 변화가 생깁니다."
flagAsCat: "나는 고양이다냥" flagAsCat: "나는 고양이다냥"
@ -313,6 +319,7 @@ copyUrl: "URL 복사"
rename: "이름 변경" rename: "이름 변경"
avatar: "아바타" avatar: "아바타"
banner: "배너" banner: "배너"
displayOfSensitiveMedia: "민감한 미디어 표시"
whenServerDisconnected: "서버와의 접속이 끊겼을 때" whenServerDisconnected: "서버와의 접속이 끊겼을 때"
disconnectedFromServer: "서버와의 연결이 끊어졌습니다" disconnectedFromServer: "서버와의 연결이 끊어졌습니다"
reload: "새로고침" reload: "새로고침"
@ -1066,6 +1073,24 @@ installed: "설치됨"
branding: "브랜딩" branding: "브랜딩"
enableServerMachineStats: "서버의 머신 사양을 공개하기" enableServerMachineStats: "서버의 머신 사양을 공개하기"
enableIdenticonGeneration: "유저마다의 Identicon 생성 유효화" enableIdenticonGeneration: "유저마다의 Identicon 생성 유효화"
turnOffToImprovePerformance: "이 기능을 끄면 성능이 향상될 수 있습니다."
createInviteCode: "초대 코드 생성"
createWithOptions: "옵션을 지정하여 생성"
createCount: "초대 수"
inviteCodeCreated: "초대 코드 생성됨"
inviteLimitExceeded: "초대 코드 생성 한도를 초과했습니다."
createLimitRemaining: "초대 한도: {limit}회 남음"
inviteLimitResetCycle: " {time}시간 이내에 최대 {limit}개의 초대 코드를 생성할 수 있습니다."
expirationDate: "만료 날짜"
noExpirationDate: "만료기간 없음"
inviteCodeUsedAt: "다음에 사용된 초대 코드"
registeredUserUsingInviteCode: "초대 코드 사용 대상"
waitingForMailAuth: "이메일 인증 보류 중"
inviteCodeCreator: "초대 코드 생성자"
usedAt: "사용 시각"
unused: "사용되지 않음"
used: "사용됨"
expired: "만료됨"
_initialAccountSetting: _initialAccountSetting:
accountCreated: "계정 생성이 완료되었습니다!" accountCreated: "계정 생성이 완료되었습니다!"
letsStartAccountSetup: "계정의 초기 설정을 진행합니다." letsStartAccountSetup: "계정의 초기 설정을 진행합니다."
@ -1376,6 +1401,9 @@ _role:
ltlAvailable: "로컬 타임라인 보이기" ltlAvailable: "로컬 타임라인 보이기"
canPublicNote: "공개 노트 허용" canPublicNote: "공개 노트 허용"
canInvite: "서버 초대 코드 발행" canInvite: "서버 초대 코드 발행"
inviteLimit: "초대 한도"
inviteLimitCycle: "초대 발급 간격"
inviteExpirationTime: "초대 만료 기간"
canManageCustomEmojis: "커스텀 이모지 관리" canManageCustomEmojis: "커스텀 이모지 관리"
driveCapacity: "드라이브 용량" driveCapacity: "드라이브 용량"
alwaysMarkNsfw: "파일을 항상 NSFW로 지정" alwaysMarkNsfw: "파일을 항상 NSFW로 지정"
@ -1438,6 +1466,7 @@ _ad:
back: "뒤로" back: "뒤로"
reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기" reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기"
hide: "보이지 않음" hide: "보이지 않음"
timezoneinfo: "요일은 서버의 표준 시간대에 따라 결정됩니다."
_forgotPassword: _forgotPassword:
enterEmail: "여기에 계정에 등록한 메일 주소를 입력해 주세요. 입력한 메일 주소로 비밀번호 재설정 링크를 발송합니다." enterEmail: "여기에 계정에 등록한 메일 주소를 입력해 주세요. 입력한 메일 주소로 비밀번호 재설정 링크를 발송합니다."
ifNoEmail: "메일 주소를 등록하지 않은 경우, 관리자에 문의해 주십시오." ifNoEmail: "메일 주소를 등록하지 않은 경우, 관리자에 문의해 주십시오."
@ -1489,6 +1518,10 @@ _aboutMisskey:
donate: "Misskey에 기부하기" donate: "Misskey에 기부하기"
morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰" morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰"
patrons: "후원자" patrons: "후원자"
_displayOfSensitiveMedia:
respect: "민감한 콘텐츠로 표시된 미디어 숨기기"
ignore: "민감한 콘텐츠로 표시된 미디어 보이기"
force: "미디어 항상 숨기기"
_instanceTicker: _instanceTicker:
none: "보이지 않음" none: "보이지 않음"
remote: "리모트 유저에게만 보이기" remote: "리모트 유저에게만 보이기"
@ -1963,6 +1996,7 @@ _deck:
introduction: "칼럼을 조합해서 나만의 인터페이스를 구성해 보아요!" introduction: "칼럼을 조합해서 나만의 인터페이스를 구성해 보아요!"
introduction2: "나중에라도 화면 우측의 + 버튼을 눌러 새 칼럼을 추가할 수 있습니다." introduction2: "나중에라도 화면 우측의 + 버튼을 눌러 새 칼럼을 추가할 수 있습니다."
widgetsIntroduction: "칼럼 메뉴의 \"위젯 편집\"에서 위젯을 추가해 주세요" widgetsIntroduction: "칼럼 메뉴의 \"위젯 편집\"에서 위젯을 추가해 주세요"
useSimpleUiForNonRootPages: "루트 이외의 페이지로 접속한 경우 UI 간략화하기"
_columns: _columns:
main: "메인" main: "메인"
widgets: "위젯" widgets: "위젯"

View File

@ -20,6 +20,7 @@ noNotes: "ບໍ່ມີຫມາຍເຫດ"
noNotifications: "ບໍ່ມີການແຈ້ງເຕືອນ" noNotifications: "ບໍ່ມີການແຈ້ງເຕືອນ"
instance: "ອີນສະແຕນ" instance: "ອີນສະແຕນ"
settings: "ກຳນົດຄ່າ" settings: "ກຳນົດຄ່າ"
notificationSettings: "ຕັ້ງຄ່າການແຈ້ງເຕືອນ"
basicSettings: "ການຕັ້ງຄ່າພື້ນຖານ" basicSettings: "ການຕັ້ງຄ່າພື້ນຖານ"
otherSettings: "ການຕັ້ງຄ່າອື່ນໆ" otherSettings: "ການຕັ້ງຄ່າອື່ນໆ"
openInWindow: "ເປີດຢູ່ໃນປ່ອງຢ້ຽມ" openInWindow: "ເປີດຢູ່ໃນປ່ອງຢ້ຽມ"
@ -48,9 +49,15 @@ delete: "ລຶບ"
deleteAndEdit: "ລົບ​ແລະ​ແກ້​ໄຂ​" deleteAndEdit: "ລົບ​ແລະ​ແກ້​ໄຂ​"
deleteAndEditConfirm: "ເຈົ້າ​ແນ່​ໃຈ​ບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ" deleteAndEditConfirm: "ເຈົ້າ​ແນ່​ໃຈ​ບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ"
addToList: "ເພີ່ມໃສ່ລາຍຊື່" addToList: "ເພີ່ມໃສ່ລາຍຊື່"
addToAntenna: "ເພີ່ມໃສ່ເສົາອາກາດ"
sendMessage: "ສົ່ງຂໍ້ຄວາມ" sendMessage: "ສົ່ງຂໍ້ຄວາມ"
copyRSS: "ສຳເນົາ RSS" copyRSS: "ສຳເນົາ RSS"
copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້" copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
copyUserId: "ສຳເນົາ ID ຜູ້ໃຊ້"
copyNoteId: "ສຳເນົາ ID ບັນທຶກ"
copyFileId: "ສຳເນົາ ID ໄຟລ໌"
copyFolderId: "ສຳເນົາ ID ໂຟນເດີ"
copyProfileUrl: "ສຳເນົາ URL ໂປຣໄຟລ໌"
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້" searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
reply: "ຕອບ​ໄປ​ທີ" reply: "ຕອບ​ໄປ​ທີ"
loadMore: "ໂຫຼດເພີ່ມເຕີມ" loadMore: "ໂຫຼດເພີ່ມເຕີມ"
@ -109,6 +116,7 @@ sensitive: "NSFW"
add: "ເພີ່ມ" add: "ເພີ່ມ"
reaction: "ປະຕິກິລິຍາ" reaction: "ປະຕິກິລິຍາ"
reactions: "ປະຕິກິລິຍາ" reactions: "ປະຕິກິລິຍາ"
attachCancel: "ເອົາໄຟລ໌ແນບ"
mute: "ປີດສຽງ" mute: "ປີດສຽງ"
unmute: "ເປີດສຽງ" unmute: "ເປີດສຽງ"
block: "ບ໋ອກ" block: "ບ໋ອກ"
@ -116,6 +124,10 @@ unblock: "ຍົກເລີກກາຮົບລັອກ"
suspend: "ລະງັບ" suspend: "ລະງັບ"
unsuspend: "ເຊົາ​ລະ​ງັບ" unsuspend: "ເຊົາ​ລະ​ງັບ"
selectList: "ເລືອກບັນຊີລາຍການ" selectList: "ເລືອກບັນຊີລາຍການ"
editList: "ແກ້ໄຂລາຍຊື່"
selectChannel: "ເລືອກຊ່ອງ"
selectAntenna: "ເລືອກເສົາອາກາດ"
editAntenna: "ແກ້ໄຂເສົາອາກາດ"
selectWidget: "ເລືອກວິກເຈັດ" selectWidget: "ເລືອກວິກເຈັດ"
editWidgets: "ແກ້ໄຂ Widget" editWidgets: "ແກ້ໄຂ Widget"
editWidgetsExit: "ສຳເລັດແລ້ວ" editWidgetsExit: "ສຳເລັດແລ້ວ"
@ -125,6 +137,7 @@ emojis: "ອີໂມຈິ"
emojiName: "ຊື່ Emoji" emojiName: "ຊື່ Emoji"
emojiUrl: "URL ອີໂມຈິ" emojiUrl: "URL ອີໂມຈິ"
addEmoji: "ຕື່ມອີໂມຈິ" addEmoji: "ຕື່ມອີໂມຈິ"
settingGuide: "ການຕັ້ງຄ່າທີ່ແນະນໍາ"
flagAsBot: "ໝາຍບັນຊີນີ້ເປັນບັອດ" flagAsBot: "ໝາຍບັນຊີນີ້ເປັນບັອດ"
flagAsCat: "ໝາຍບັນຊີນີ້ເປັນແມວ" flagAsCat: "ໝາຍບັນຊີນີ້ເປັນແມວ"
flagAsCatDescription: "ເປີດໃຊ້ຕົວເລືອກນີ້ເພື່ອໝາຍບັນຊີນີ້ເປັນແມວ" flagAsCatDescription: "ເປີດໃຊ້ຕົວເລືອກນີ້ເພື່ອໝາຍບັນຊີນີ້ເປັນແມວ"
@ -133,10 +146,13 @@ flagShowTimelineRepliesDescription: "ສະແດງການຕອບກັບ
autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່" autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່"
addAccount: "ເພີ່ມບັນຊີ" addAccount: "ເພີ່ມບັນຊີ"
loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ" loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ"
showOnRemote: "ເບິ່ງຢູ່ໃນຕົວຢ່າງໄລຍະໄກ"
general: "ທົ່ວໄປ" general: "ທົ່ວໄປ"
wallpaper: "ພາບພື້ນຫລັງ" wallpaper: "ພາບພື້ນຫລັງ"
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ" setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
removeWallpaper: "ລຶບຮູບວໍເປເປີອອກ"
searchWith: "ຊອກຫາ: {q}" searchWith: "ຊອກຫາ: {q}"
youHaveNoLists: "ທ່ານ​ບໍ່​ມີ​ລາຍ​ການ​ໃດໆ​"
proxyAccount: "ບັນຊີພຣັອກຊີ" proxyAccount: "ບັນຊີພຣັອກຊີ"
host: "ໂຮດສ" host: "ໂຮດສ"
selectUser: "ເລືອກຜູ້ໃຊ້" selectUser: "ເລືອກຜູ້ໃຊ້"
@ -155,7 +171,9 @@ operations: "ການດຳເນີນງານ"
software: "ຊອບແວ" software: "ຊອບແວ"
version: "ສະບັບ" version: "ສະບັບ"
metadata: "Metadata" metadata: "Metadata"
withNFiles: "{n} ໄຟລ໌(s)"
monitor: "ຈໍພາບ" monitor: "ຈໍພາບ"
jobQueue: "ຄິວວຽກ"
cpuAndMemory: "CPU ແລະ ຫນ່ວຍຄວາມຈໍາ" cpuAndMemory: "CPU ແລະ ຫນ່ວຍຄວາມຈໍາ"
network: "ເຄືອຂ່າຍ" network: "ເຄືອຂ່າຍ"
disk: "ດິສກ໌" disk: "ດິສກ໌"
@ -343,6 +361,7 @@ _widgets:
timeline: "​ເສັ້ນກຳ​ນົດ​ເວ​ລາ​" timeline: "​ເສັ້ນກຳ​ນົດ​ເວ​ລາ​"
activity: "ກິດຈະກຳ" activity: "ກິດຈະກຳ"
federation: "ສະຫະພັນ" federation: "ສະຫະພັນ"
jobQueue: "ຄິວວຽກ"
_userList: _userList:
chooseList: "ເລືອກບັນຊີລາຍການ" chooseList: "ເລືອກບັນຊີລາຍການ"
_cw: _cw:

View File

@ -481,6 +481,7 @@ windowMinimize: "Minimera"
windowRestore: "Återställ" windowRestore: "Återställ"
pleaseDonate: "Misskey är en gratis programvara som används på {host}. Donera gärna för att göra utvecklingen ständigt, tack!" pleaseDonate: "Misskey är en gratis programvara som används på {host}. Donera gärna för att göra utvecklingen ständigt, tack!"
resetPasswordConfirm: "Återställ verkligen ditt lösenord?" resetPasswordConfirm: "Återställ verkligen ditt lösenord?"
dataSaver: "Databesparing"
_achievements: _achievements:
_types: _types:
_open3windows: _open3windows:

View File

@ -1,7 +1,7 @@
--- ---
_lang_: "ภาษาไทย" _lang_: "ภาษาไทย"
headlineMisskey: "เชื่อมต่อเครือข่ายโดยโน้ต" headlineMisskey: "เชื่อมต่อระบบ Network ด้วย Note"
introMisskey: "ยินดีต้อนรับจ้าาา! Misskey เป็นบริการไมโครบล็อกโอเพ่นซอร์ส แบบการกระจายอำนาจ\nสร้าง \"โน้ต\" เพื่อแบ่งปันความคิดของคุณกับทุกคนรอบตัวคุณกันเถอะ 📡\nด้วยการ \"รีแอคชั่นผู้คน\" คุณยังสามารถแสดงความรู้สึกของคุณเกี่ยวกับบันทึกของทุกคนได้อย่างรวดเร็ว 👍\n\nแล้วมาท่องสำรวจโลกใบใหม่กันเถอะ! 🚀" introMisskey: "ยินดีต้อนรับทุกคนจ้า! Misskey คือ บริการไมโครบล็อกกิ้ง (MicroBlogging) แบบกระจายศูนย์อำนาจ (Decentralized) \n\nเขียน \"โน้ต (Note)\" เพื่อส่งต่อเรื่องราวของคุณให้ทั้งโลกได้รับรู้📡\nและอย่าลืมที่จะ \"React\" กับเรื่องราวของคนอื่น ๆ ด้วย! 👍\n\nมุ่งสู่โลกใบใหม่กันเถอะ🚀"
poweredByMisskeyDescription: "{name} เป็นส่วนหนึ่งในบริการที่ถูกขับเคลื่อนโดยแพลตฟอร์มโอเพ่นซอร์ส <b>Misskey</b> (เรียกว่า \"อินสแตนซ์ Misskey\")" poweredByMisskeyDescription: "{name} เป็นส่วนหนึ่งในบริการที่ถูกขับเคลื่อนโดยแพลตฟอร์มโอเพ่นซอร์ส <b>Misskey</b> (เรียกว่า \"อินสแตนซ์ Misskey\")"
monthAndDay: "{month}/{day}" monthAndDay: "{month}/{day}"
search: "ค้นหา" search: "ค้นหา"
@ -339,7 +339,7 @@ thisYear: "ปีนี้"
thisMonth: "เดือนนี้" thisMonth: "เดือนนี้"
today: "วันนี้" today: "วันนี้"
dayX: "{day}" dayX: "{day}"
monthX: "{เดือน}" monthX: "เดือน {month}"
yearX: "{year}" yearX: "{year}"
pages: "หน้า" pages: "หน้า"
integration: "รวบรวม" integration: "รวบรวม"
@ -1996,6 +1996,7 @@ _deck:
introduction: "สร้างอินเทอร์เฟซที่สมบูรณ์แบบสำหรับคุณโดยจัดเรียงคอลัมน์ได้อย่างอิสระ!" introduction: "สร้างอินเทอร์เฟซที่สมบูรณ์แบบสำหรับคุณโดยจัดเรียงคอลัมน์ได้อย่างอิสระ!"
introduction2: "คลิกที่เครื่องหมาย + ทางขวาของหน้าจอเพื่อเพิ่มคอลัมน์ใหม่ทุกครั้งที่คุณต้องการ" introduction2: "คลิกที่เครื่องหมาย + ทางขวาของหน้าจอเพื่อเพิ่มคอลัมน์ใหม่ทุกครั้งที่คุณต้องการ"
widgetsIntroduction: "กรุณาเลือก \"แก้ไขวิดเจ็ต\" ในเมนูคอลัมน์และเพิ่มวิดเจ็ต" widgetsIntroduction: "กรุณาเลือก \"แก้ไขวิดเจ็ต\" ในเมนูคอลัมน์และเพิ่มวิดเจ็ต"
useSimpleUiForNonRootPages: "แสดง UI ของ Root Page อย่างง่าย "
_columns: _columns:
main: "หลัก" main: "หลัก"
widgets: "วิดเจ็ต" widgets: "วิดเจ็ต"

View File

@ -156,6 +156,8 @@ addEmoji: "添加表情符号"
settingGuide: "推荐配置" settingGuide: "推荐配置"
cacheRemoteFiles: "缓存远程文件" cacheRemoteFiles: "缓存远程文件"
cacheRemoteFilesDescription: "当禁用此设定时远程文件将直接从远程服务器载入。禁用后会减小储存空间需求,但是会增加流量,因为缩略图不会被生成。" cacheRemoteFilesDescription: "当禁用此设定时远程文件将直接从远程服务器载入。禁用后会减小储存空间需求,但是会增加流量,因为缩略图不会被生成。"
cacheRemoteSensitiveFiles: "缓存远程敏感媒体文件"
cacheRemoteSensitiveFilesDescription: "如果禁用这项设定,远程服务器的敏感媒体将不会被缓存,而是直接链接。"
flagAsBot: "这是一个机器人账号" flagAsBot: "这是一个机器人账号"
flagAsBotDescription: "如果此账户由程序控制,请启用此项。启用后,此标志可以帮助其他开发人员防止机器人之间产生无限互动的行为,并让 Misskey 的内部系统将此账户识别为机器人。" flagAsBotDescription: "如果此账户由程序控制,请启用此项。启用后,此标志可以帮助其他开发人员防止机器人之间产生无限互动的行为,并让 Misskey 的内部系统将此账户识别为机器人。"
flagAsCat: "将这个账户设定为一只猫" flagAsCat: "将这个账户设定为一只猫"
@ -1072,7 +1074,20 @@ branding: "品牌"
enableServerMachineStats: "公开服务器硬件统计信息" enableServerMachineStats: "公开服务器硬件统计信息"
enableIdenticonGeneration: "启用生成用户 Identicon" enableIdenticonGeneration: "启用生成用户 Identicon"
turnOffToImprovePerformance: "关闭该选项可以提高性能。" turnOffToImprovePerformance: "关闭该选项可以提高性能。"
createInviteCode: "发行邀请码"
createWithOptions: "使用选项来创建"
createCount: "发行数"
inviteCodeCreated: "已创建邀请码" inviteCodeCreated: "已创建邀请码"
inviteLimitExceeded: "可供发行的邀请码已达上限。"
createLimitRemaining: "可供发行的邀请码:剩余{limit}个"
inviteLimitResetCycle: "可以在{time}内发行最多{limit}个邀请码。"
expirationDate: "有效日期"
noExpirationDate: "不设置有效日期"
inviteCodeUsedAt: "邀请码被使用的日期和时间"
registeredUserUsingInviteCode: "使用了邀请码的用户"
waitingForMailAuth: "等待验证电子邮件"
inviteCodeCreator: "发行邀请码的用户"
usedAt: "使用时间"
unused: "未使用" unused: "未使用"
used: "已使用" used: "已使用"
expired: "已过期" expired: "已过期"
@ -1386,6 +1401,9 @@ _role:
ltlAvailable: "查看本地时间线" ltlAvailable: "查看本地时间线"
canPublicNote: "允许公开发帖" canPublicNote: "允许公开发帖"
canInvite: "发放服务器邀请码" canInvite: "发放服务器邀请码"
inviteLimit: "可发行邀请码的数量"
inviteLimitCycle: "邀请码的发行间隔"
inviteExpirationTime: "邀请码的有效日期"
canManageCustomEmojis: "管理自定义表情符号" canManageCustomEmojis: "管理自定义表情符号"
driveCapacity: "网盘容量" driveCapacity: "网盘容量"
alwaysMarkNsfw: "总是将文件标记为 NSFW" alwaysMarkNsfw: "总是将文件标记为 NSFW"
@ -1978,6 +1996,7 @@ _deck:
introduction: "将各列进行组合以创建您自己的界面!" introduction: "将各列进行组合以创建您自己的界面!"
introduction2: "您可以随时通过屏幕右侧的 + 来添加列" introduction2: "您可以随时通过屏幕右侧的 + 来添加列"
widgetsIntroduction: "从列菜单中,选择“小工具编辑”来添加小工具" widgetsIntroduction: "从列菜单中,选择“小工具编辑”来添加小工具"
useSimpleUiForNonRootPages: "用简易UI表示非根页面"
_columns: _columns:
main: "主列" main: "主列"
widgets: "小工具" widgets: "小工具"

View File

@ -1996,6 +1996,7 @@ _deck:
introduction: "組合欄位來製作屬於自己的介面吧!" introduction: "組合欄位來製作屬於自己的介面吧!"
introduction2: "您可以隨時透過按畫面右方的 + 來添加欄位。" introduction2: "您可以隨時透過按畫面右方的 + 來添加欄位。"
widgetsIntroduction: "請從欄位的選單中,選擇「編輯小工具」來添加小工具" widgetsIntroduction: "請從欄位的選單中,選擇「編輯小工具」來添加小工具"
useSimpleUiForNonRootPages: "用簡易UI顯示非根頁面"
_columns: _columns:
main: "主列" main: "主列"
widgets: "小工具" widgets: "小工具"

View File

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "13.14.0-beta.5", "version": "13.14.0-beta.6",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -57,24 +57,24 @@
"@aws-sdk/client-s3": "3.367.0", "@aws-sdk/client-s3": "3.367.0",
"@aws-sdk/lib-storage": "3.367.0", "@aws-sdk/lib-storage": "3.367.0",
"@aws-sdk/node-http-handler": "3.360.0", "@aws-sdk/node-http-handler": "3.360.0",
"@bull-board/api": "5.6.0", "@bull-board/api": "5.6.1",
"@bull-board/fastify": "5.6.0", "@bull-board/fastify": "5.6.1",
"@bull-board/ui": "5.6.0", "@bull-board/ui": "5.6.1",
"@discordapp/twemoji": "14.1.2", "@discordapp/twemoji": "14.1.2",
"@fastify/accepts": "4.2.0", "@fastify/accepts": "4.2.0",
"@fastify/cookie": "8.3.0", "@fastify/cookie": "8.3.0",
"@fastify/cors": "8.3.0", "@fastify/cors": "8.3.0",
"@fastify/http-proxy": "9.2.1", "@fastify/http-proxy": "9.2.1",
"@fastify/multipart": "7.7.0", "@fastify/multipart": "7.7.1",
"@fastify/static": "6.10.2", "@fastify/static": "6.10.2",
"@fastify/view": "8.0.0", "@fastify/view": "8.0.0",
"@nestjs/common": "10.0.5", "@nestjs/common": "10.1.0",
"@nestjs/core": "10.0.5", "@nestjs/core": "10.1.0",
"@nestjs/testing": "10.0.5", "@nestjs/testing": "10.1.0",
"@peertube/http-signature": "1.7.0", "@peertube/http-signature": "1.7.0",
"@sinonjs/fake-timers": "10.3.0", "@sinonjs/fake-timers": "10.3.0",
"@swc/cli": "0.1.62", "@swc/cli": "0.1.62",
"@swc/core": "1.3.69", "@swc/core": "1.3.70",
"accepts": "1.3.8", "accepts": "1.3.8",
"ajv": "8.12.0", "ajv": "8.12.0",
"archiver": "5.3.1", "archiver": "5.3.1",
@ -82,7 +82,7 @@
"autwh": "0.1.0", "autwh": "0.1.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "2.0.5", "blurhash": "2.0.5",
"bullmq": "4.3.0", "bullmq": "4.4.0",
"cacheable-lookup": "7.0.0", "cacheable-lookup": "7.0.0",
"cbor": "9.0.0", "cbor": "9.0.0",
"chalk": "5.3.0", "chalk": "5.3.0",
@ -94,7 +94,7 @@
"date-fns": "2.30.0", "date-fns": "2.30.0",
"deep-email-validator": "0.1.21", "deep-email-validator": "0.1.21",
"escape-regexp": "0.0.1", "escape-regexp": "0.0.1",
"fastify": "4.19.2", "fastify": "4.20.0",
"feed": "4.2.2", "feed": "4.2.2",
"file-type": "18.5.0", "file-type": "18.5.0",
"fluent-ffmpeg": "2.1.2", "fluent-ffmpeg": "2.1.2",

View File

@ -4,10 +4,9 @@ import { IsNull, In, MoreThan, Not } from 'typeorm';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js';
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, Muting, MutingsRepository, UserListJoiningsRepository, UsersRepository } from '@/models/index.js'; import type { BlockingsRepository, FollowingsRepository, InstancesRepository, Muting, MutingsRepository, UserListJoiningsRepository, UsersRepository } from '@/models/index.js';
import type { RelationshipJobData, ThinUser } from '@/queue/types.js'; import type { RelationshipJobData, ThinUser } from '@/queue/types.js';
import type { User } from '@/models/entities/User.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';

View File

@ -2,6 +2,7 @@ import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { JSDOM } from 'jsdom'; import { JSDOM } from 'jsdom';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import * as Redis from 'ioredis';
import type { Instance } from '@/models/entities/Instance.js'; import type { Instance } from '@/models/entities/Instance.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -10,7 +11,6 @@ import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import type { DOMWindow } from 'jsdom'; import type { DOMWindow } from 'jsdom';
import * as Redis from 'ioredis';
type NodeInfo = { type NodeInfo = {
openRegistrations?: unknown; openRegistrations?: unknown;

View File

@ -574,7 +574,7 @@ export class NoteCreateService implements OnApplicationShutdown {
where: { where: {
userId: data.reply.userId, userId: data.reply.userId,
threadId: data.reply.threadId ?? data.reply.id, threadId: data.reply.threadId ?? data.reply.id,
} },
}); });
if (!isThreadMuted) { if (!isThreadMuted) {

View File

@ -8,8 +8,9 @@ import type { LocalUser, RemoteUser } from '@/models/entities/User.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { UtilityService } from '@/core/UtilityService.js'; import { UtilityService } from '@/core/UtilityService.js';
import { WebfingerService } from '@/core/WebfingerService.js'; import { ILink, WebfingerService } from '@/core/WebfingerService.js';
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js'; import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js';
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -27,6 +28,7 @@ export class RemoteUserResolveService {
private utilityService: UtilityService, private utilityService: UtilityService,
private webfingerService: WebfingerService, private webfingerService: WebfingerService,
private remoteLoggerService: RemoteLoggerService, private remoteLoggerService: RemoteLoggerService,
private apDbResolverService: ApDbResolverService,
private apPersonService: ApPersonService, private apPersonService: ApPersonService,
) { ) {
this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user'); this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
@ -67,6 +69,22 @@ export class RemoteUserResolveService {
if (user == null) { if (user == null) {
const self = await this.resolveSelf(acctLower); const self = await this.resolveSelf(acctLower);
if (self.href.startsWith(this.config.url)) {
const local = this.apDbResolverService.parseUri(self.href);
if (local.local && local.type === 'users') {
// the LR points to local
return (await this.apDbResolverService
.getUserFromApId(self.href)
.then((u) => {
if (u == null) {
throw new Error('local user not found');
} else {
return u;
}
})) as LocalUser;
}
}
this.logger.succ(`return new remote user: ${chalk.magenta(acctLower)}`); this.logger.succ(`return new remote user: ${chalk.magenta(acctLower)}`);
return await this.apPersonService.createPerson(self.href); return await this.apPersonService.createPerson(self.href);
} }
@ -119,7 +137,7 @@ export class RemoteUserResolveService {
} }
@bindThis @bindThis
private async resolveSelf(acctLower: string) { private async resolveSelf(acctLower: string): Promise<ILink> {
this.logger.info(`WebFinger for ${chalk.yellow(acctLower)}`); this.logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
const finger = await this.webfingerService.webfinger(acctLower).catch(err => { const finger = await this.webfingerService.webfinger(acctLower).catch(err => {
this.logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ err.statusCode ?? err.message }`); this.logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ err.statusCode ?? err.message }`);

View File

@ -1,5 +1,6 @@
import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common'; import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core'; import { ModuleRef } from '@nestjs/core';
import { IsNull } from 'typeorm';
import type { LocalUser, PartialLocalUser, PartialRemoteUser, RemoteUser, User } from '@/models/entities/User.js'; import type { LocalUser, PartialLocalUser, PartialRemoteUser, RemoteUser, User } from '@/models/entities/User.js';
import { IdentifiableError } from '@/misc/identifiable-error.js'; import { IdentifiableError } from '@/misc/identifiable-error.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
@ -21,9 +22,8 @@ import { UserBlockingService } from '@/core/UserBlockingService.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { CacheService } from '@/core/CacheService.js'; import { CacheService } from '@/core/CacheService.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import Logger from '../logger.js';
import { IsNull } from 'typeorm';
import { AccountMoveService } from '@/core/AccountMoveService.js'; import { AccountMoveService } from '@/core/AccountMoveService.js';
import Logger from '../logger.js';
const logger = new Logger('following/create'); const logger = new Logger('following/create');
@ -322,7 +322,7 @@ export class UserFollowingService implements OnModuleInit {
where: { where: {
followerId: follower.id, followerId: follower.id,
followeeId: followee.id, followeeId: followee.id,
} },
}); });
if (following === null || !following.follower || !following.followee) { if (following === null || !following.follower || !following.followee) {
@ -412,8 +412,8 @@ export class UserFollowingService implements OnModuleInit {
followerId: user.id, followerId: user.id,
followee: { followee: {
movedToUri: IsNull(), movedToUri: IsNull(),
} },
} },
}); });
const nonMovedFollowers = await this.followingsRepository.count({ const nonMovedFollowers = await this.followingsRepository.count({
relations: { relations: {
@ -423,8 +423,8 @@ export class UserFollowingService implements OnModuleInit {
followeeId: user.id, followeeId: user.id,
follower: { follower: {
movedToUri: IsNull(), movedToUri: IsNull(),
} },
} },
}); });
await this.usersRepository.update( await this.usersRepository.update(
{ id: user.id }, { id: user.id },
@ -646,7 +646,7 @@ export class UserFollowingService implements OnModuleInit {
where: { where: {
followeeId: followee.id, followeeId: followee.id,
followerId: follower.id, followerId: follower.id,
} },
}); });
if (!following || !following.followee || !following.follower) return; if (!following || !following.followee || !following.follower) return;

View File

@ -52,7 +52,7 @@ export class VideoProcessingService {
query({ query({
thumbnail: '1', thumbnail: '1',
url, url,
}) }),
); );
} }
} }

View File

@ -6,12 +6,12 @@ import { query as urlQuery } from '@/misc/prelude/url.js';
import { HttpRequestService } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
type ILink = { export type ILink = {
href: string; href: string;
rel?: string; rel?: string;
}; };
type IWebFinger = { export type IWebFinger = {
links: ILink[]; links: ILink[];
subject: string; subject: string;
}; };

View File

@ -3,8 +3,8 @@ import { DI } from '@/di-symbols.js';
import type { AbuseUserReportsRepository } from '@/models/index.js'; import type { AbuseUserReportsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js'; import { awaitAll } from '@/misc/prelude/await-all.js';
import type { AbuseUserReport } from '@/models/entities/AbuseUserReport.js'; import type { AbuseUserReport } from '@/models/entities/AbuseUserReport.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
@Injectable() @Injectable()
export class AbuseUserReportEntityService { export class AbuseUserReportEntityService {

View File

@ -4,8 +4,8 @@ import type { AuthSessionsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js'; import { awaitAll } from '@/misc/prelude/await-all.js';
import type { AuthSession } from '@/models/entities/AuthSession.js'; import type { AuthSession } from '@/models/entities/AuthSession.js';
import type { User } from '@/models/entities/User.js'; import type { User } from '@/models/entities/User.js';
import { AppEntityService } from './AppEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { AppEntityService } from './AppEntityService.js';
@Injectable() @Injectable()
export class AuthSessionEntityService { export class AuthSessionEntityService {

View File

@ -50,7 +50,7 @@ export class ChannelEntityService {
const hasUnreadNote = meId ? await this.noteUnreadsRepository.exist({ const hasUnreadNote = meId ? await this.noteUnreadsRepository.exist({
where: { where: {
noteChannelId: channel.id, noteChannelId: channel.id,
userId: meId userId: meId,
}, },
}) : undefined; }) : undefined;

View File

@ -4,8 +4,8 @@ import type { FollowRequestsRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js'; import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js'; import type { User } from '@/models/entities/User.js';
import type { FollowRequest } from '@/models/entities/FollowRequest.js'; import type { FollowRequest } from '@/models/entities/FollowRequest.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
@Injectable() @Injectable()
export class FollowRequestEntityService { export class FollowRequestEntityService {

View File

@ -3,8 +3,8 @@ import { DI } from '@/di-symbols.js';
import type { GalleryLikesRepository } from '@/models/index.js'; import type { GalleryLikesRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js'; import type { } from '@/models/entities/Blocking.js';
import type { GalleryLike } from '@/models/entities/GalleryLike.js'; import type { GalleryLike } from '@/models/entities/GalleryLike.js';
import { GalleryPostEntityService } from './GalleryPostEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { GalleryPostEntityService } from './GalleryPostEntityService.js';
@Injectable() @Injectable()
export class GalleryLikeEntityService { export class GalleryLikeEntityService {

View File

@ -4,8 +4,8 @@ import type { ModerationLogsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js'; import { awaitAll } from '@/misc/prelude/await-all.js';
import type { } from '@/models/entities/Blocking.js'; import type { } from '@/models/entities/Blocking.js';
import type { ModerationLog } from '@/models/entities/ModerationLog.js'; import type { ModerationLog } from '@/models/entities/ModerationLog.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
@Injectable() @Injectable()
export class ModerationLogEntityService { export class ModerationLogEntityService {

View File

@ -4,8 +4,8 @@ import type { NoteFavoritesRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js'; import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js'; import type { User } from '@/models/entities/User.js';
import type { NoteFavorite } from '@/models/entities/NoteFavorite.js'; import type { NoteFavorite } from '@/models/entities/NoteFavorite.js';
import { NoteEntityService } from './NoteEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { NoteEntityService } from './NoteEntityService.js';
@Injectable() @Injectable()
export class NoteFavoriteEntityService { export class NoteFavoriteEntityService {

View File

@ -4,8 +4,8 @@ import type { PageLikesRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js'; import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js'; import type { User } from '@/models/entities/User.js';
import type { PageLike } from '@/models/entities/PageLike.js'; import type { PageLike } from '@/models/entities/PageLike.js';
import { PageEntityService } from './PageEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { PageEntityService } from './PageEntityService.js';
@Injectable() @Injectable()
export class PageLikeEntityService { export class PageLikeEntityService {

View File

@ -3,8 +3,8 @@ import { DI } from '@/di-symbols.js';
import type { SigninsRepository } from '@/models/index.js'; import type { SigninsRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js'; import type { } from '@/models/entities/Blocking.js';
import type { Signin } from '@/models/entities/Signin.js'; import type { Signin } from '@/models/entities/Signin.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
@Injectable() @Injectable()
export class SigninEntityService { export class SigninEntityService {

View File

@ -1,11 +1,11 @@
import { Writable, WritableOptions } from "node:stream"; import { Writable, WritableOptions } from 'node:stream';
export class DevNull extends Writable implements NodeJS.WritableStream { export class DevNull extends Writable implements NodeJS.WritableStream {
constructor(opts?: WritableOptions) { constructor(opts?: WritableOptions) {
super(opts); super(opts);
} }
_write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) { _write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) {
setImmediate(cb); setImmediate(cb);
} }
} }

View File

@ -5,10 +5,10 @@ const CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
export const ulidRegExp = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/; export const ulidRegExp = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/;
export function parseUlid(id: string): { date: Date; } { export function parseUlid(id: string): { date: Date; } {
const timestamp = id.slice(0, 10); const timestamp = id.slice(0, 10);
let time = 0; let time = 0;
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
time = time * 32 + CHARS.indexOf(timestamp[i]); time = time * 32 + CHARS.indexOf(timestamp[i]);
} }
return { date: new Date(time) }; return { date: new Date(time) };
} }

View File

@ -10,7 +10,7 @@ export async function awaitAll<T>(obj: Promiseable<T>): Promise<T> {
const resolvedValues = await Promise.all(values.map(value => const resolvedValues = await Promise.all(values.map(value =>
(!value || !value.constructor || value.constructor.name !== 'Object') (!value || !value.constructor || value.constructor.name !== 'Object')
? value ? value
: awaitAll(value) : awaitAll(value),
)); ));
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {

View File

@ -49,7 +49,6 @@ import { User } from '@/models/entities/User.js';
import { UserIp } from '@/models/entities/UserIp.js'; import { UserIp } from '@/models/entities/UserIp.js';
import { UserKeypair } from '@/models/entities/UserKeypair.js'; import { UserKeypair } from '@/models/entities/UserKeypair.js';
import { UserList } from '@/models/entities/UserList.js'; import { UserList } from '@/models/entities/UserList.js';
import { UserListFavorite } from './entities/UserListFavorite.js';
import { UserListJoining } from '@/models/entities/UserListJoining.js'; import { UserListJoining } from '@/models/entities/UserListJoining.js';
import { UserNotePining } from '@/models/entities/UserNotePining.js'; import { UserNotePining } from '@/models/entities/UserNotePining.js';
import { UserPending } from '@/models/entities/UserPending.js'; import { UserPending } from '@/models/entities/UserPending.js';
@ -64,6 +63,7 @@ import { Role } from '@/models/entities/Role.js';
import { RoleAssignment } from '@/models/entities/RoleAssignment.js'; import { RoleAssignment } from '@/models/entities/RoleAssignment.js';
import { Flash } from '@/models/entities/Flash.js'; import { Flash } from '@/models/entities/Flash.js';
import { FlashLike } from '@/models/entities/FlashLike.js'; import { FlashLike } from '@/models/entities/FlashLike.js';
import { UserListFavorite } from './entities/UserListFavorite.js';
import type { Repository } from 'typeorm'; import type { Repository } from 'typeorm';
export { export {

View File

@ -9,10 +9,10 @@ import type { DriveFile } from '@/models/entities/DriveFile.js';
import type { Note } from '@/models/entities/Note.js'; import type { Note } from '@/models/entities/Note.js';
import { EmailService } from '@/core/EmailService.js'; import { EmailService } from '@/core/EmailService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { SearchService } from '@/core/SearchService.js';
import { QueueLoggerService } from '../QueueLoggerService.js'; import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq'; import type * as Bull from 'bullmq';
import type { DbUserDeleteJobData } from '../types.js'; import type { DbUserDeleteJobData } from '../types.js';
import { SearchService } from "@/core/SearchService.js";
@Injectable() @Injectable()
export class DeleteAccountProcessorService { export class DeleteAccountProcessorService {

View File

@ -1,16 +1,16 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import type * as Bull from 'bullmq';
import { UserFollowingService } from '@/core/UserFollowingService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import { RelationshipJobData } from '../types.js';
import type { UsersRepository } from '@/models/index.js'; import type { UsersRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { LocalUser, RemoteUser } from '@/models/entities/User.js'; import { LocalUser, RemoteUser } from '@/models/entities/User.js';
import { RelationshipJobData } from '../types.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
@Injectable() @Injectable()
export class RelationshipProcessorService { export class RelationshipProcessorService {

View File

@ -3,6 +3,8 @@ import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path'; import { dirname } from 'node:path';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import rename from 'rename'; import rename from 'rename';
import sharp from 'sharp';
import { sharpBmp } from 'sharp-read-bmp';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { DriveFile, DriveFilesRepository } from '@/models/index.js'; import type { DriveFile, DriveFilesRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -18,11 +20,9 @@ import { contentDisposition } from '@/misc/content-disposition.js';
import { FileInfoService } from '@/core/FileInfoService.js'; import { FileInfoService } from '@/core/FileInfoService.js';
import { LoggerService } from '@/core/LoggerService.js'; import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
import { isMimeImage } from '@/misc/is-mime-image.js'; import { isMimeImage } from '@/misc/is-mime-image.js';
import sharp from 'sharp';
import { sharpBmp } from 'sharp-read-bmp';
import { correctFilename } from '@/misc/correct-filename.js'; import { correctFilename } from '@/misc/correct-filename.js';
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
const _filename = fileURLToPath(import.meta.url); const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename); const _dirname = dirname(_filename);
@ -180,8 +180,8 @@ export class FileServerService {
reply.header('Content-Disposition', reply.header('Content-Disposition',
contentDisposition( contentDisposition(
'inline', 'inline',
correctFilename(file.filename, image.ext) correctFilename(file.filename, image.ext),
) ),
); );
return image.data; return image.data;
} }
@ -278,11 +278,11 @@ export class FileServerService {
}; };
} else { } else {
const data = (await sharpBmp(file.path, file.mime, { animated: !('static' in request.query) })) const data = (await sharpBmp(file.path, file.mime, { animated: !('static' in request.query) }))
.resize({ .resize({
height: 'emoji' in request.query ? 128 : 320, height: 'emoji' in request.query ? 128 : 320,
withoutEnlargement: true, withoutEnlargement: true,
}) })
.webp(webpDefault); .webp(webpDefault);
image = { image = {
data, data,
@ -355,8 +355,8 @@ export class FileServerService {
reply.header('Content-Disposition', reply.header('Content-Disposition',
contentDisposition( contentDisposition(
'inline', 'inline',
correctFilename(file.filename, image.ext) correctFilename(file.filename, image.ext),
) ),
); );
return image.data; return image.data;
} catch (e) { } catch (e) {

View File

@ -1,18 +1,18 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { IsNull } from 'typeorm'; import { IsNull } from 'typeorm';
import vary from 'vary'; import vary from 'vary';
import fastifyAccepts from '@fastify/accepts';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { UsersRepository } from '@/models/index.js'; import type { UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { escapeAttribute, escapeValue } from '@/misc/prelude/xml.js'; import { escapeAttribute, escapeValue } from '@/misc/prelude/xml.js';
import type { User } from '@/models/entities/User.js'; import type { User } from '@/models/entities/User.js';
import * as Acct from '@/misc/acct.js'; import * as Acct from '@/misc/acct.js';
import { NodeinfoServerService } from './NodeinfoServerService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import type { FindOptionsWhere } from 'typeorm';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { NodeinfoServerService } from './NodeinfoServerService.js';
import type { FindOptionsWhere } from 'typeorm';
import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
import fastifyAccepts from '@fastify/accepts';
@Injectable() @Injectable()
export class WellKnownServerService { export class WellKnownServerService {

View File

@ -13,9 +13,9 @@ import { EmailService } from '@/core/EmailService.js';
import { LocalUser } from '@/models/entities/User.js'; import { LocalUser } from '@/models/entities/User.js';
import { FastifyReplyError } from '@/misc/fastify-reply-error.js'; import { FastifyReplyError } from '@/misc/fastify-reply-error.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
import { SigninService } from './SigninService.js'; import { SigninService } from './SigninService.js';
import type { FastifyRequest, FastifyReply } from 'fastify'; import type { FastifyRequest, FastifyReply } from 'fastify';
import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
@Injectable() @Injectable()
export class SignupApiService { export class SignupApiService {

View File

@ -91,7 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (queryarry) { if (queryarry) {
emojis = emojis.filter(emoji => emojis = emojis.filter(emoji =>
queryarry.includes(`:${emoji.name}:`) queryarry.includes(`:${emoji.name}:`),
); );
} else { } else {
emojis = emojis.filter(emoji => emojis = emojis.filter(emoji =>

View File

@ -5,8 +5,8 @@ import type { UsersRepository, BlockingsRepository } from '@/models/index.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['account'], tags: ['account'],
@ -88,7 +88,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
where: { where: {
blockerId: blocker.id, blockerId: blocker.id,
blockeeId: blockee.id, blockeeId: blockee.id,
} },
}); });
if (!exist) { if (!exist) {

View File

@ -2,8 +2,8 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { ClipNotesRepository, ClipsRepository } from '@/models/index.js'; import type { ClipNotesRepository, ClipsRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['account', 'notes', 'clips'], tags: ['account', 'notes', 'clips'],

View File

@ -5,8 +5,8 @@ import type { UsersRepository, FollowingsRepository } from '@/models/index.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['following', 'users'], tags: ['following', 'users'],

View File

@ -5,8 +5,8 @@ import type { UsersRepository, FollowingsRepository } from '@/models/index.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['following', 'users'], tags: ['following', 'users'],

View File

@ -23,7 +23,7 @@ export const meta = {
id: 'e5b3b9f0-2b8f-4b9f-9c1f-8c5c1b2e1b1a', id: 'e5b3b9f0-2b8f-4b9f-9c1f-8c5c1b2e1b1a',
kind: 'permission', kind: 'permission',
}, },
} },
} as const; } as const;
export const paramDef = { export const paramDef = {

View File

@ -267,7 +267,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const instance = await this.metaService.fetch(true); const instance = await this.metaService.fetch(true);
const ads = await this.adsRepository.createQueryBuilder("ads") const ads = await this.adsRepository.createQueryBuilder('ads')
.where('ads.expiresAt > :now', { now: new Date() }) .where('ads.expiresAt > :now', { now: new Date() })
.andWhere('ads.startsAt <= :now', { now: new Date() }) .andWhere('ads.startsAt <= :now', { now: new Date() })
.andWhere(new Brackets(qb => { .andWhere(new Brackets(qb => {

View File

@ -4,8 +4,8 @@ import type { NotesRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['notes'], tags: ['notes'],

View File

@ -3,8 +3,8 @@ import type { NotesRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['notes'], tags: ['notes'],

View File

@ -3,8 +3,8 @@ import type { PromoReadsRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['notes'], tags: ['notes'],

View File

@ -35,7 +35,7 @@ export const meta = {
code: 'NO_SUCH_REGISTRATION', code: 'NO_SUCH_REGISTRATION',
id: ' b09d8066-8064-5613-efb6-0e963b21d012', id: ' b09d8066-8064-5613-efb6-0e963b21d012',
}, },
} },
} as const; } as const;
export const paramDef = { export const paramDef = {

View File

@ -5,8 +5,8 @@ import type { NotesRepository, UsersRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['users'], tags: ['users'],

View File

@ -3,9 +3,9 @@ import { isUserRelated } from '@/misc/is-user-related.js';
import type { Packed } from '@/misc/json-schema.js'; import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import Channel from '../channel.js'; import Channel from '../channel.js';
import { StreamMessages } from '../types.js'; import { StreamMessages } from '../types.js';
import { RoleService } from '@/core/RoleService.js';
class RoleTimelineChannel extends Channel { class RoleTimelineChannel extends Channel {
public readonly chName = 'roleTimeline'; public readonly chName = 'roleTimeline';

View File

@ -19,10 +19,10 @@
"@rollup/plugin-json": "6.0.0", "@rollup/plugin-json": "6.0.0",
"@rollup/plugin-replace": "5.0.2", "@rollup/plugin-replace": "5.0.2",
"@rollup/pluginutils": "5.0.2", "@rollup/pluginutils": "5.0.2",
"@syuilo/aiscript": "0.13.3", "@syuilo/aiscript": "0.14.0",
"@tabler/icons-webfont": "2.25.0", "@tabler/icons-webfont": "2.25.0",
"@vitejs/plugin-vue": "4.2.3", "@vitejs/plugin-vue": "4.2.3",
"@vue-macros/reactivity-transform": "0.3.14", "@vue-macros/reactivity-transform": "0.3.15",
"@vue/compiler-sfc": "3.3.4", "@vue/compiler-sfc": "3.3.4",
"astring": "1.8.6", "astring": "1.8.6",
"autosize": "6.0.1", "autosize": "6.0.1",
@ -54,7 +54,7 @@
"prismjs": "1.29.0", "prismjs": "1.29.0",
"punycode": "2.3.0", "punycode": "2.3.0",
"querystring": "0.2.1", "querystring": "0.2.1",
"rollup": "3.26.2", "rollup": "3.26.3",
"s-age": "1.1.2", "s-age": "1.1.2",
"sanitize-html": "2.11.0", "sanitize-html": "2.11.0",
"sass": "1.63.6", "sass": "1.63.6",
@ -76,24 +76,24 @@
"vuedraggable": "next" "vuedraggable": "next"
}, },
"devDependencies": { "devDependencies": {
"@storybook/addon-actions": "7.0.27", "@storybook/addon-actions": "7.1.0",
"@storybook/addon-essentials": "7.0.27", "@storybook/addon-essentials": "7.1.0",
"@storybook/addon-interactions": "7.0.27", "@storybook/addon-interactions": "7.1.0",
"@storybook/addon-links": "7.0.27", "@storybook/addon-links": "7.1.0",
"@storybook/addon-storysource": "7.0.27", "@storybook/addon-storysource": "7.1.0",
"@storybook/addons": "7.0.27", "@storybook/addons": "7.1.0",
"@storybook/blocks": "7.0.27", "@storybook/blocks": "7.1.0",
"@storybook/core-events": "7.0.27", "@storybook/core-events": "7.1.0",
"@storybook/jest": "0.1.0", "@storybook/jest": "0.1.0",
"@storybook/manager-api": "7.0.27", "@storybook/manager-api": "7.1.0",
"@storybook/preview-api": "7.0.27", "@storybook/preview-api": "7.1.0",
"@storybook/react": "7.0.27", "@storybook/react": "7.1.0",
"@storybook/react-vite": "7.0.27", "@storybook/react-vite": "7.1.0",
"@storybook/testing-library": "0.2.0", "@storybook/testing-library": "0.2.0",
"@storybook/theming": "7.0.27", "@storybook/theming": "7.1.0",
"@storybook/types": "7.0.27", "@storybook/types": "7.1.0",
"@storybook/vue3": "7.0.27", "@storybook/vue3": "7.1.0",
"@storybook/vue3-vite": "7.0.27", "@storybook/vue3-vite": "7.1.0",
"@testing-library/jest-dom": "5.16.5", "@testing-library/jest-dom": "5.16.5",
"@testing-library/vue": "7.0.0", "@testing-library/vue": "7.0.0",
"@types/escape-regexp": "0.0.1", "@types/escape-regexp": "0.0.1",
@ -131,7 +131,7 @@
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"start-server-and-test": "2.0.0", "start-server-and-test": "2.0.0",
"storybook": "7.0.27", "storybook": "7.1.0",
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
"summaly": "github:misskey-dev/summaly", "summaly": "github:misskey-dev/summaly",
"vite-plugin-turbosnap": "1.0.2", "vite-plugin-turbosnap": "1.0.2",

View File

@ -259,6 +259,17 @@ useTooltip(renoteButton, async (showing) => {
}, {}, 'closed'); }, {}, 'closed');
}); });
type Visibility = 'public' | 'home' | 'followers' | 'specified';
// defaultStore.state.visibilitystringstring
function smallerVisibility(a: Visibility | string, b: Visibility | string): Visibility {
if (a === 'specified' || b === 'specified') return 'specified';
if (a === 'followers' || b === 'followers') return 'followers';
if (a === 'home' || b === 'home') return 'home';
// if (a === 'public' || b === 'public')
return 'public';
}
function renote(viaKeyboard = false) { function renote(viaKeyboard = false) {
pleaseLogin(); pleaseLogin();
showMovedDialog(); showMovedDialog();
@ -309,7 +320,12 @@ function renote(viaKeyboard = false) {
os.popup(MkRippleEffect, { x, y }, {}, 'end'); os.popup(MkRippleEffect, { x, y }, {}, 'end');
} }
const configuredVisibility = defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility;
const localOnly = defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly;
os.api('notes/create', { os.api('notes/create', {
localOnly,
visibility: smallerVisibility(appearNote.visibility, configuredVisibility),
renoteId: appearNote.id, renoteId: appearNote.id,
}).then(() => { }).then(() => {
os.toast(i18n.ts.renoted); os.toast(i18n.ts.renoted);

View File

@ -907,6 +907,7 @@ defineExpose({
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
gap: 4px; gap: 4px;
margin-bottom: -10px;
} }
.headerLeft { .headerLeft {
@ -1024,7 +1025,7 @@ defineExpose({
} }
.targetNote { .targetNote {
padding: 0 20px 16px 20px; padding: 10px 20px 16px 20px;
} }
.withQuote { .withQuote {

View File

@ -15,13 +15,13 @@
</div> </div>
<div :class="$style.status"> <div :class="$style.status">
<div :class="$style.statusItem"> <div :class="$style.statusItem">
<p :class="$style.statusItemLabel">{{ i18n.ts.notes }}</p><span :class="$style.statusItemValue">{{ user.notesCount }}</span> <p :class="$style.statusItemLabel">{{ i18n.ts.notes }}</p><span :class="$style.statusItemValue">{{ number(user.notesCount) }}</span>
</div> </div>
<div :class="$style.statusItem"> <div v-if="isFfVisibleForMe(user)" :class="$style.statusItem">
<p :class="$style.statusItemLabel">{{ i18n.ts.following }}</p><span :class="$style.statusItemValue">{{ user.followingCount }}</span> <p :class="$style.statusItemLabel">{{ i18n.ts.following }}</p><span :class="$style.statusItemValue">{{ number(user.followingCount) }}</span>
</div> </div>
<div :class="$style.statusItem"> <div v-if="isFfVisibleForMe(user)" :class="$style.statusItem">
<p :class="$style.statusItemLabel">{{ i18n.ts.followers }}</p><span :class="$style.statusItemValue">{{ user.followersCount }}</span> <p :class="$style.statusItemLabel">{{ i18n.ts.followers }}</p><span :class="$style.statusItemValue">{{ number(user.followersCount) }}</span>
</div> </div>
</div> </div>
<MkFollowButton v-if="$i && user.id != $i.id" :class="$style.follow" :user="user" mini/> <MkFollowButton v-if="$i && user.id != $i.id" :class="$style.follow" :user="user" mini/>
@ -31,9 +31,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import * as misskey from 'misskey-js'; import * as misskey from 'misskey-js';
import MkFollowButton from '@/components/MkFollowButton.vue'; import MkFollowButton from '@/components/MkFollowButton.vue';
import number from '@/filters/number';
import { userPage } from '@/filters/user'; import { userPage } from '@/filters/user';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { $i } from '@/account'; import { $i } from '@/account';
import { isFfVisibleForMe } from '@/scripts/isFfVisibleForMe';
defineProps<{ defineProps<{
user: misskey.entities.UserDetailed; user: misskey.entities.UserDetailed;

View File

@ -30,11 +30,11 @@
<div :class="$style.statusItemLabel">{{ i18n.ts.notes }}</div> <div :class="$style.statusItemLabel">{{ i18n.ts.notes }}</div>
<div>{{ number(user.notesCount) }}</div> <div>{{ number(user.notesCount) }}</div>
</div> </div>
<div :class="$style.statusItem"> <div v-if="isFfVisibleForMe(user)" :class="$style.statusItem">
<div :class="$style.statusItemLabel">{{ i18n.ts.following }}</div> <div :class="$style.statusItemLabel">{{ i18n.ts.following }}</div>
<div>{{ number(user.followingCount) }}</div> <div>{{ number(user.followingCount) }}</div>
</div> </div>
<div :class="$style.statusItem"> <div v-if="isFfVisibleForMe(user)" :class="$style.statusItem">
<div :class="$style.statusItemLabel">{{ i18n.ts.followers }}</div> <div :class="$style.statusItemLabel">{{ i18n.ts.followers }}</div>
<div>{{ number(user.followersCount) }}</div> <div>{{ number(user.followersCount) }}</div>
</div> </div>
@ -61,6 +61,7 @@ import number from '@/filters/number';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { $i } from '@/account'; import { $i } from '@/account';
import { isFfVisibleForMe } from '@/scripts/isFfVisibleForMe';
const props = defineProps<{ const props = defineProps<{
showing: boolean; showing: boolean;

View File

@ -33,7 +33,7 @@ import MkTextarea from '@/components/MkTextarea.vue';
import MkInput from '@/components/MkInput.vue'; import MkInput from '@/components/MkInput.vue';
import { useRouter } from '@/router'; import { useRouter } from '@/router';
const PRESET_DEFAULT = `/// @ 0.13.3 const PRESET_DEFAULT = `/// @ 0.14.0
var name = "" var name = ""
@ -51,7 +51,7 @@ Ui:render([
]) ])
`; `;
const PRESET_OMIKUJI = `/// @ 0.13.3 const PRESET_OMIKUJI = `/// @ 0.14.0
// //
// //
@ -94,7 +94,7 @@ Ui:render([
]) ])
`; `;
const PRESET_SHUFFLE = `/// @ 0.13.3 const PRESET_SHUFFLE = `/// @ 0.14.0
// //
let string = "ペペロンチーノ" let string = "ペペロンチーノ"
@ -173,7 +173,7 @@ var cursor = 0
do() do()
`; `;
const PRESET_QUIZ = `/// @ 0.13.3 const PRESET_QUIZ = `/// @ 0.14.0
let title = '地理クイズ' let title = '地理クイズ'
let qas = [{ let qas = [{
@ -286,7 +286,7 @@ qaEls.push(Ui:C:container({
Ui:render(qaEls) Ui:render(qaEls)
`; `;
const PRESET_TIMELINE = `/// @ 0.13.3 const PRESET_TIMELINE = `/// @ 0.14.0
// API // API
@fetch() { @fetch() {

View File

@ -100,15 +100,15 @@
</dl> </dl>
</div> </div>
<div class="status"> <div class="status">
<MkA v-click-anime :to="userPage(user)"> <MkA :to="userPage(user)">
<b>{{ number(user.notesCount) }}</b> <b>{{ number(user.notesCount) }}</b>
<span>{{ i18n.ts.notes }}</span> <span>{{ i18n.ts.notes }}</span>
</MkA> </MkA>
<MkA v-click-anime :to="userPage(user, 'following')"> <MkA v-if="isFfVisibleForMe(user)" :to="userPage(user, 'following')">
<b>{{ number(user.followingCount) }}</b> <b>{{ number(user.followingCount) }}</b>
<span>{{ i18n.ts.following }}</span> <span>{{ i18n.ts.following }}</span>
</MkA> </MkA>
<MkA v-click-anime :to="userPage(user, 'followers')"> <MkA v-if="isFfVisibleForMe(user)" :to="userPage(user, 'followers')">
<b>{{ number(user.followersCount) }}</b> <b>{{ number(user.followersCount) }}</b>
<span>{{ i18n.ts.followers }}</span> <span>{{ i18n.ts.followers }}</span>
</MkA> </MkA>
@ -160,6 +160,7 @@ import { dateString } from '@/filters/date';
import { confetti } from '@/scripts/confetti'; import { confetti } from '@/scripts/confetti';
import MkNotes from '@/components/MkNotes.vue'; import MkNotes from '@/components/MkNotes.vue';
import { api } from '@/os'; import { api } from '@/os';
import { isFfVisibleForMe } from '@/scripts/isFfVisibleForMe';
const XPhotos = defineAsyncComponent(() => import('./index.photos.vue')); const XPhotos = defineAsyncComponent(() => import('./index.photos.vue'));
const XActivity = defineAsyncComponent(() => import('./index.activity.vue')); const XActivity = defineAsyncComponent(() => import('./index.activity.vue'));

View File

@ -0,0 +1,11 @@
import * as misskey from 'misskey-js';
import { $i } from '@/account';
export function isFfVisibleForMe(user: misskey.entities.UserDetailed): boolean {
if ($i && $i.id === user.id) return true;
if (user.ffVisibility === 'private') return false;
if (user.ffVisibility === 'followers' && !user.isFollowing) return false;
return true;
}

File diff suppressed because it is too large Load Diff