Firefish v1.0.5-dev19
This commit is contained in:
parent
bd7273fd5e
commit
be83fa27ac
40 changed files with 750 additions and 654 deletions
|
@ -526,12 +526,12 @@ objectStorageBaseUrl: "Basis-URL"
|
||||||
objectStorageBaseUrlDesc: "Die als Referenz verwendete URL. Verwendest du einen CDN
|
objectStorageBaseUrlDesc: "Die als Referenz verwendete URL. Verwendest du einen CDN
|
||||||
oder Proxy, gib dessen URL an. \nFür S3 verwende 'https://<bucket>.s3.amazonaws.com'.
|
oder Proxy, gib dessen URL an. \nFür S3 verwende 'https://<bucket>.s3.amazonaws.com'.
|
||||||
Für GCS o.ä. verwende 'https://storage.googleapis.com/<bucket>'."
|
Für GCS o.ä. verwende 'https://storage.googleapis.com/<bucket>'."
|
||||||
objectStorageBucket: "Eimer"
|
objectStorageBucket: "Bucket"
|
||||||
objectStorageBucketDesc: "Bitte gib den Namen des Buckets an, der bei deinem Anbieter
|
objectStorageBucketDesc: "Bitte gib den Namen des Buckets an, der bei deinem Anbieter
|
||||||
verwendet wird."
|
verwendet wird."
|
||||||
objectStoragePrefix: "Prefix"
|
objectStoragePrefix: "Prefix"
|
||||||
objectStoragePrefixDesc: "Dateien werden in Ordnern unter diesem Prefix gespeichert."
|
objectStoragePrefixDesc: "Dateien werden in Ordnern unter diesem Prefix gespeichert."
|
||||||
objectStorageEndpoint: "Limit"
|
objectStorageEndpoint: "Endpunkt"
|
||||||
objectStorageEndpointDesc: "Im Falle von S3 leerlassen, für andere Anbieter den relevanten
|
objectStorageEndpointDesc: "Im Falle von S3 leerlassen, für andere Anbieter den relevanten
|
||||||
Endpoint im Format „<host>“ oder „<host>:<port>“ angeben."
|
Endpoint im Format „<host>“ oder „<host>:<port>“ angeben."
|
||||||
objectStorageRegion: "Region"
|
objectStorageRegion: "Region"
|
||||||
|
@ -1034,6 +1034,7 @@ _accountDelete:
|
||||||
_ad:
|
_ad:
|
||||||
back: "Zurück"
|
back: "Zurück"
|
||||||
reduceFrequencyOfThisAd: "Diese Werbeanzeige weniger anzeigen"
|
reduceFrequencyOfThisAd: "Diese Werbeanzeige weniger anzeigen"
|
||||||
|
adsBy: Community-Banner von {by}
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "Gib die Email-Adresse ein, mit der du dich registriert hast. An diese
|
enterEmail: "Gib die Email-Adresse ein, mit der du dich registriert hast. An diese
|
||||||
wird ein Link gesendet, mit dem du dein Passwort zurücksetzen kannst."
|
wird ein Link gesendet, mit dem du dein Passwort zurücksetzen kannst."
|
||||||
|
@ -1240,6 +1241,7 @@ _wordMute:
|
||||||
soft: "Leicht"
|
soft: "Leicht"
|
||||||
hard: "Schwer"
|
hard: "Schwer"
|
||||||
mutedNotes: "Stummgeschaltete Beiträge"
|
mutedNotes: "Stummgeschaltete Beiträge"
|
||||||
|
muteLangs: Stummgeschaltete Sprachen
|
||||||
_instanceMute:
|
_instanceMute:
|
||||||
instanceMuteDescription: "Schaltet alle Beiträge/Boosts stumm, die von den gelisteten
|
instanceMuteDescription: "Schaltet alle Beiträge/Boosts stumm, die von den gelisteten
|
||||||
Servern stammen, inklusive Antworten von Nutzern an einen Nutzer eines stummgeschalteten
|
Servern stammen, inklusive Antworten von Nutzern an einen Nutzer eines stummgeschalteten
|
||||||
|
@ -2212,3 +2214,5 @@ indexable: Indexierbar
|
||||||
languageForTranslation: Übersetzungssprache veröffentlichen
|
languageForTranslation: Übersetzungssprache veröffentlichen
|
||||||
openServerInfo: Anzeigen von Serverinformationen durch Anklicken des Server-Tickers
|
openServerInfo: Anzeigen von Serverinformationen durch Anklicken des Server-Tickers
|
||||||
in einem Beitrag
|
in einem Beitrag
|
||||||
|
vibrate: Vibrationen abspielen
|
||||||
|
clickToShowPatterns: Klicken um Modul-Muster anzuzeigen
|
||||||
|
|
|
@ -616,7 +616,7 @@ emptyToDisableSmtpAuth: "ユーザー名とパスワードを空欄にするこ
|
||||||
smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する"
|
smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する"
|
||||||
smtpSecureInfo: "STARTTLS使用時はオフにします。"
|
smtpSecureInfo: "STARTTLS使用時はオフにします。"
|
||||||
testEmail: "配信テスト"
|
testEmail: "配信テスト"
|
||||||
wordMute: "ワードミュート"
|
wordMute: "単語または言語のミュート"
|
||||||
regexpError: "正規表現エラー"
|
regexpError: "正規表現エラー"
|
||||||
regexpErrorDescription: "{tab}ワードミュートの{line}行目の正規表現にエラーが発生しました:"
|
regexpErrorDescription: "{tab}ワードミュートの{line}行目の正規表現にエラーが発生しました:"
|
||||||
instanceMute: "サーバーミュート"
|
instanceMute: "サーバーミュート"
|
||||||
|
@ -694,7 +694,7 @@ no: "いいえ"
|
||||||
driveFilesCount: "ドライブのファイル数"
|
driveFilesCount: "ドライブのファイル数"
|
||||||
driveUsage: "ドライブ使用量"
|
driveUsage: "ドライブ使用量"
|
||||||
noCrawle: "クローラーによるインデックスを拒否"
|
noCrawle: "クローラーによるインデックスを拒否"
|
||||||
noCrawleDescription: "検索エンジンにあなたのプロフィールや投稿、ページなどのコンテンツを登録(インデックス)しないよう要請します。"
|
noCrawleDescription: "Web検索にあなたのプロフィールや投稿、ページなどのコンテンツを登録(インデックス)しないよう要請します。"
|
||||||
lockedAccountInfo: "フォローを承認制にしても、投稿の公開範囲を「フォロワー」にしない限り、誰でもあなたの投稿を見られます。"
|
lockedAccountInfo: "フォローを承認制にしても、投稿の公開範囲を「フォロワー」にしない限り、誰でもあなたの投稿を見られます。"
|
||||||
alwaysMarkSensitive: "デフォルトでメディアを閲覧注意にする"
|
alwaysMarkSensitive: "デフォルトでメディアを閲覧注意にする"
|
||||||
loadRawImages: "添付画像のサムネイルをオリジナル画質にする"
|
loadRawImages: "添付画像のサムネイルをオリジナル画質にする"
|
||||||
|
@ -811,7 +811,7 @@ instanceSecurity: "サーバーのセキュリティー"
|
||||||
secureModeInfo: "認証情報の無いリモートサーバーからのリクエストに応えません。"
|
secureModeInfo: "認証情報の無いリモートサーバーからのリクエストに応えません。"
|
||||||
privateMode: "非公開モード"
|
privateMode: "非公開モード"
|
||||||
privateModeInfo: "有効にすると、許可したサーバーのみからリクエストを受け付けます。"
|
privateModeInfo: "有効にすると、許可したサーバーのみからリクエストを受け付けます。"
|
||||||
allowedInstances: "許可されたサーバー"
|
allowedInstances: "許可するサーバー"
|
||||||
allowedInstancesDescription: "許可したいサーバーのホストを改行で区切って設定します。非公開モードだけで有効です。"
|
allowedInstancesDescription: "許可したいサーバーのホストを改行で区切って設定します。非公開モードだけで有効です。"
|
||||||
previewNoteText: "本文をプレビュー"
|
previewNoteText: "本文をプレビュー"
|
||||||
customCss: "カスタムCSS"
|
customCss: "カスタムCSS"
|
||||||
|
@ -1518,7 +1518,7 @@ _profile:
|
||||||
youCanIncludeHashtags: "ハッシュタグを含められます。"
|
youCanIncludeHashtags: "ハッシュタグを含められます。"
|
||||||
metadata: "追加情報"
|
metadata: "追加情報"
|
||||||
metadataEdit: "追加情報を編集"
|
metadataEdit: "追加情報を編集"
|
||||||
metadataDescription: "プロフィールに追加情報を表示できます。{a}タグまたは{l}タグを{rel}とともに追加すると、プロフィールのリンクを本人認証できます。"
|
metadataDescription: "プロフィールに追加情報を表示できます。{rel}属性をつけた{a}タグや{l}タグを含むページをリンクすることで、リンクの本人確認もできます!"
|
||||||
metadataLabel: "ラベル"
|
metadataLabel: "ラベル"
|
||||||
metadataContent: "内容"
|
metadataContent: "内容"
|
||||||
changeAvatar: "アバター画像を変更"
|
changeAvatar: "アバター画像を変更"
|
||||||
|
@ -2019,6 +2019,9 @@ postSearch: "このサーバーの投稿検索"
|
||||||
indexableDescription: MastodonやFirefishなどの検索機能に、あなたの投稿が表示されるのを許可します。
|
indexableDescription: MastodonやFirefishなどの検索機能に、あなたの投稿が表示されるのを許可します。
|
||||||
makePrivate: "秘密にする"
|
makePrivate: "秘密にする"
|
||||||
makePrivateConfirm: "リモートサーバーに削除リクエストを送信し、投稿の公開範囲を「秘密」にして他の人から見られないようにします。実行しますか?"
|
makePrivateConfirm: "リモートサーバーに削除リクエストを送信し、投稿の公開範囲を「秘密」にして他の人から見られないようにします。実行しますか?"
|
||||||
|
clickToShowPatterns: クリックしてトラックを表示
|
||||||
|
vibrate: 振動を有効にする
|
||||||
|
indexable: 投稿検索に登録
|
||||||
_iconSets:
|
_iconSets:
|
||||||
bold: "太め"
|
bold: "太め"
|
||||||
light: "細め"
|
light: "細め"
|
||||||
|
|
|
@ -937,7 +937,8 @@ _accountDelete:
|
||||||
inProgress: "正在删除"
|
inProgress: "正在删除"
|
||||||
_ad:
|
_ad:
|
||||||
back: "返回"
|
back: "返回"
|
||||||
reduceFrequencyOfThisAd: "减少此广告的频率"
|
reduceFrequencyOfThisAd: "减少此横幅的频率"
|
||||||
|
adsBy: 社区横幅(作者:{by})
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "请输入您注册账号时用的电子邮箱地址,密码重置链接将发送至该邮箱上。"
|
enterEmail: "请输入您注册账号时用的电子邮箱地址,密码重置链接将发送至该邮箱上。"
|
||||||
ifNoEmail: "如果您在注册时没有输入电子邮件地址,请联系服务器管理员。"
|
ifNoEmail: "如果您在注册时没有输入电子邮件地址,请联系服务器管理员。"
|
||||||
|
@ -1996,3 +1997,4 @@ indexable: 可索引的
|
||||||
languageForTranslation: 帖子翻译语言
|
languageForTranslation: 帖子翻译语言
|
||||||
vibrate: 播放振动
|
vibrate: 播放振动
|
||||||
openServerInfo: 点击帖子上的服务器滚动条时显示服务器信息
|
openServerInfo: 点击帖子上的服务器滚动条时显示服务器信息
|
||||||
|
clickToShowPatterns: 点击显示模块模式
|
||||||
|
|
|
@ -21,7 +21,7 @@ basicSettings: "基本設定"
|
||||||
otherSettings: "其他設定"
|
otherSettings: "其他設定"
|
||||||
openInWindow: "在新視窗開啟"
|
openInWindow: "在新視窗開啟"
|
||||||
profile: "個人檔案"
|
profile: "個人檔案"
|
||||||
timeline: "時間線"
|
timeline: "時間軸"
|
||||||
noAccountDescription: "此用戶還沒有自我介紹。"
|
noAccountDescription: "此用戶還沒有自我介紹。"
|
||||||
login: "登入"
|
login: "登入"
|
||||||
loggingIn: "登入中"
|
loggingIn: "登入中"
|
||||||
|
@ -149,12 +149,12 @@ flagAsBot: "標記此帳號是機器人"
|
||||||
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整Firefish內部系統將本帳戶識別為機器人。"
|
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整Firefish內部系統將本帳戶識別為機器人。"
|
||||||
flagAsCat: "你是喵咪嗎?w😺"
|
flagAsCat: "你是喵咪嗎?w😺"
|
||||||
flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示!"
|
flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示!"
|
||||||
flagShowTimelineReplies: "在時間線上顯示貼文的回覆"
|
flagShowTimelineReplies: "在時間軸上顯示貼文的回覆"
|
||||||
flagShowTimelineRepliesDescription: "啟用時,時間線除了顯示用戶的貼文以外,還會顯示用戶對其他貼文的回覆。"
|
flagShowTimelineRepliesDescription: "啟用時,時間軸除了顯示用戶的貼文以外,還會顯示用戶對其他貼文的回覆。"
|
||||||
autoAcceptFollowed: "自動准予追隨中使用者的追隨請求"
|
autoAcceptFollowed: "自動准予追隨中使用者的追隨請求"
|
||||||
addAccount: "添加帳戶"
|
addAccount: "添加帳戶"
|
||||||
loginFailed: "登入失敗"
|
loginFailed: "登入失敗"
|
||||||
showOnRemote: "轉到所在伺服器顯示"
|
showOnRemote: "開啟來源頁面"
|
||||||
general: "一般"
|
general: "一般"
|
||||||
wallpaper: "桌布"
|
wallpaper: "桌布"
|
||||||
setWallpaper: "設定桌布"
|
setWallpaper: "設定桌布"
|
||||||
|
@ -324,9 +324,9 @@ dayX: "{day}日"
|
||||||
monthX: "{month}月"
|
monthX: "{month}月"
|
||||||
yearX: "{year}年"
|
yearX: "{year}年"
|
||||||
pages: "頁面"
|
pages: "頁面"
|
||||||
enableLocalTimeline: "開啟本地時間線"
|
enableLocalTimeline: "開啟本地時間軸"
|
||||||
enableGlobalTimeline: "啟用公開時間線"
|
enableGlobalTimeline: "啟用公開時間軸"
|
||||||
disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和板主仍可訪問所有的時間線。"
|
disablingTimelinesInfo: "即使您關閉了時間軸功能,管理員和板主仍可訪問所有的時間軸。"
|
||||||
registration: "註冊"
|
registration: "註冊"
|
||||||
enableRegistration: "開啟新使用者註冊"
|
enableRegistration: "開啟新使用者註冊"
|
||||||
invite: "邀請"
|
invite: "邀請"
|
||||||
|
@ -386,7 +386,7 @@ administrator: "管理員"
|
||||||
token: "權杖"
|
token: "權杖"
|
||||||
twoStepAuthentication: "兩階段驗證"
|
twoStepAuthentication: "兩階段驗證"
|
||||||
moderator: "板主"
|
moderator: "板主"
|
||||||
moderation: "言論調節"
|
moderation: "管理"
|
||||||
nUsersMentioned: "提到了{n}"
|
nUsersMentioned: "提到了{n}"
|
||||||
securityKey: "安全金鑰"
|
securityKey: "安全金鑰"
|
||||||
securityKeyName: "金鑰名稱"
|
securityKeyName: "金鑰名稱"
|
||||||
|
@ -483,7 +483,7 @@ promotion: "推廣"
|
||||||
promote: "推廣"
|
promote: "推廣"
|
||||||
numberOfDays: "有效天數"
|
numberOfDays: "有效天數"
|
||||||
hideThisNote: "隱藏此貼文"
|
hideThisNote: "隱藏此貼文"
|
||||||
showFeaturedNotesInTimeline: "在時間線上顯示熱門推薦"
|
showFeaturedNotesInTimeline: "在時間軸上顯示熱門推薦"
|
||||||
objectStorage: "Object Storage (物件儲存)"
|
objectStorage: "Object Storage (物件儲存)"
|
||||||
useObjectStorage: "使用Object Storage"
|
useObjectStorage: "使用Object Storage"
|
||||||
objectStorageBaseUrl: "根URL"
|
objectStorageBaseUrl: "根URL"
|
||||||
|
@ -503,7 +503,7 @@ objectStorageUseProxyDesc: "如果不使用代理進行API連接,請關閉"
|
||||||
objectStorageSetPublicRead: "上傳時設定為\"public-read\""
|
objectStorageSetPublicRead: "上傳時設定為\"public-read\""
|
||||||
serverLogs: "伺服器日誌"
|
serverLogs: "伺服器日誌"
|
||||||
deleteAll: "刪除所有記錄"
|
deleteAll: "刪除所有記錄"
|
||||||
showFixedPostForm: "於時間線頁頂顯示「發送貼文」方框"
|
showFixedPostForm: "於時間軸頁頂顯示「發送貼文」方框"
|
||||||
newNoteRecived: "發現新的貼文"
|
newNoteRecived: "發現新的貼文"
|
||||||
sounds: "音效"
|
sounds: "音效"
|
||||||
listen: "聆聽"
|
listen: "聆聽"
|
||||||
|
@ -671,7 +671,7 @@ no: "取消"
|
||||||
driveFilesCount: "雲端硬碟檔案數量"
|
driveFilesCount: "雲端硬碟檔案數量"
|
||||||
driveUsage: "雲端硬碟使用量"
|
driveUsage: "雲端硬碟使用量"
|
||||||
noCrawle: "拒絕搜尋引擎索引"
|
noCrawle: "拒絕搜尋引擎索引"
|
||||||
noCrawleDescription: "要求網路搜尋引擎不要索引你的個人資料頁、貼文及頁面等。"
|
noCrawleDescription: "要求外部搜尋引擎不要收錄(索引)你的內容(個人檔案、貼文、頁面等)。"
|
||||||
lockedAccountInfo: "即使你通過了追隨者請求,除非你將貼文的可見性設定為 「追隨者」,否則任何人都能看見你的貼文。"
|
lockedAccountInfo: "即使你通過了追隨者請求,除非你將貼文的可見性設定為 「追隨者」,否則任何人都能看見你的貼文。"
|
||||||
alwaysMarkSensitive: "默認將圖像/影像標記為敏感內容"
|
alwaysMarkSensitive: "默認將圖像/影像標記為敏感內容"
|
||||||
loadRawImages: "以原始圖檔顯示附件圖檔的縮圖"
|
loadRawImages: "以原始圖檔顯示附件圖檔的縮圖"
|
||||||
|
@ -689,7 +689,7 @@ experimentalFeatures: "實驗中的功能"
|
||||||
developer: "開發者"
|
developer: "開發者"
|
||||||
makeExplorable: "使自己的帳戶能夠在“探索”頁面中顯示"
|
makeExplorable: "使自己的帳戶能夠在“探索”頁面中顯示"
|
||||||
makeExplorableDescription: "如果關閉,帳戶將不會被顯示在\"探索\"頁面中。"
|
makeExplorableDescription: "如果關閉,帳戶將不會被顯示在\"探索\"頁面中。"
|
||||||
showGapBetweenNotesInTimeline: "分開顯示時間線上的貼文"
|
showGapBetweenNotesInTimeline: "分開顯示時間軸上的貼文"
|
||||||
duplicate: "複製"
|
duplicate: "複製"
|
||||||
left: "左"
|
left: "左"
|
||||||
center: "置中"
|
center: "置中"
|
||||||
|
@ -735,7 +735,7 @@ inChannelSearch: "頻道内搜尋"
|
||||||
useReactionPickerForContextMenu: "點擊右鍵開啟反應工具欄"
|
useReactionPickerForContextMenu: "點擊右鍵開啟反應工具欄"
|
||||||
typingUsers: "{users}輸入中"
|
typingUsers: "{users}輸入中"
|
||||||
jumpToSpecifiedDate: "跳轉到特定日期"
|
jumpToSpecifiedDate: "跳轉到特定日期"
|
||||||
showingPastTimeline: "顯示過往的時間線"
|
showingPastTimeline: "顯示過往的時間軸"
|
||||||
clear: "清除"
|
clear: "清除"
|
||||||
markAllAsRead: "全部標示為已讀"
|
markAllAsRead: "全部標示為已讀"
|
||||||
goBack: "返回"
|
goBack: "返回"
|
||||||
|
@ -823,7 +823,7 @@ unmuteThread: "將貼文串的靜音解除"
|
||||||
ffVisibility: "連接的公開範圍"
|
ffVisibility: "連接的公開範圍"
|
||||||
ffVisibilityDescription: "您可以設定您的關注/關注者資訊的公開範圍。"
|
ffVisibilityDescription: "您可以設定您的關注/關注者資訊的公開範圍。"
|
||||||
continueThread: "查看更多貼文"
|
continueThread: "查看更多貼文"
|
||||||
deleteAccountConfirm: "將要刪除帳戶。是否確定?"
|
deleteAccountConfirm: "此帳戶將被刪除,是否繼續?"
|
||||||
incorrectPassword: "密碼錯誤。"
|
incorrectPassword: "密碼錯誤。"
|
||||||
voteConfirm: "確定投給「{choice}」?"
|
voteConfirm: "確定投給「{choice}」?"
|
||||||
hide: "隱藏"
|
hide: "隱藏"
|
||||||
|
@ -934,6 +934,7 @@ _accountDelete:
|
||||||
_ad:
|
_ad:
|
||||||
back: "返回"
|
back: "返回"
|
||||||
reduceFrequencyOfThisAd: "降低此橫幅的頻率"
|
reduceFrequencyOfThisAd: "降低此橫幅的頻率"
|
||||||
|
adsBy: 社群橫幅(作者:{by})
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "請輸入您的帳戶註冊的電子郵件地址。 密碼重置連結將被發送到該電子郵件地址。"
|
enterEmail: "請輸入您的帳戶註冊的電子郵件地址。 密碼重置連結將被發送到該電子郵件地址。"
|
||||||
ifNoEmail: "如果您還沒有註冊您的電子郵件地址,請聯繫管理員。"
|
ifNoEmail: "如果您還沒有註冊您的電子郵件地址,請聯繫管理員。"
|
||||||
|
@ -1111,14 +1112,14 @@ _wordMute:
|
||||||
muteWords: "加入靜音文字"
|
muteWords: "加入靜音文字"
|
||||||
muteWordsDescription: "用空格分隔指定AND,用換行分隔指定OR。"
|
muteWordsDescription: "用空格分隔指定AND,用換行分隔指定OR。"
|
||||||
muteWordsDescription2: "將關鍵字用斜線括起來表示正規表達式。"
|
muteWordsDescription2: "將關鍵字用斜線括起來表示正規表達式。"
|
||||||
softDescription: "隱藏時間線中指定條件的貼文。"
|
softDescription: "隱藏時間軸中指定條件的貼文。"
|
||||||
hardDescription: "具有指定條件的貼文將不添加到時間線。 即使您更改條件,未被添加的貼文也會被排除在外。"
|
hardDescription: "符合指定條件的貼文將不添加到時間軸。 即使您更改條件,未被添加的貼文也會被排除在外。"
|
||||||
soft: "軟性靜音"
|
soft: "軟性靜音"
|
||||||
hard: "硬性靜音"
|
hard: "硬性靜音"
|
||||||
mutedNotes: "已靜音的貼文"
|
mutedNotes: "已靜音的貼文"
|
||||||
muteLangsDescription2: '使用語言代碼。例: en, fr, ja, zh.'
|
muteLangsDescription2: '使用語言代碼。例: en, fr, ja, zh.'
|
||||||
lang: 語言
|
lang: 語言
|
||||||
langDescription: 將指定語言的貼文從時間線中隱藏。
|
langDescription: 將指定語言的貼文從時間軸中隱藏。
|
||||||
muteLangs: 被靜音的語言
|
muteLangs: 被靜音的語言
|
||||||
muteLangsDescription: OR條件以空格或換行進行分隔。
|
muteLangsDescription: OR條件以空格或換行進行分隔。
|
||||||
_instanceMute:
|
_instanceMute:
|
||||||
|
@ -1230,16 +1231,16 @@ _tutorial:
|
||||||
step2_1: "首先,請完成你的個人資料。"
|
step2_1: "首先,請完成你的個人資料。"
|
||||||
step2_2: "通過提供一些關於你自己的資料,其他人會更容易了解他們是否想看到你的貼文或關注你。"
|
step2_2: "通過提供一些關於你自己的資料,其他人會更容易了解他們是否想看到你的貼文或關注你。"
|
||||||
step3_1: "現在是時候追隨一些人了!"
|
step3_1: "現在是時候追隨一些人了!"
|
||||||
step3_2: "你的主頁和社交時間線是基於你所追蹤的人,所以試著先追蹤幾個帳戶。\n點擊個人資料右上角的加號圈就可以關注它。"
|
step3_2: "你的主頁和社交時間軸是基於你所追蹤的人,所以試著先追蹤幾個帳戶。\n點擊個人資料右上角的加號按鈕就可以關注它。"
|
||||||
step4_1: "讓我們出去找你。"
|
step4_1: "讓我們出去找你。"
|
||||||
step4_2: "作為第一則貼文,有些人喜歡發 {introduction} 或單純發一個 \"hello world!\""
|
step4_2: "作為第一則貼文,有些人喜歡發 {introduction} 或單純發一個 \"hello world!\""
|
||||||
step5_1: "時間線,到處都是時間線!"
|
step5_1: "時間軸,到處都是時間軸!"
|
||||||
step5_2: "您的伺服器已啟用了{timelines}個時間線。"
|
step5_2: "您的伺服器已啟用了{timelines}個時間軸。"
|
||||||
step5_3: "首頁 {icon} 時間線是顯示你追蹤的帳號的貼文。"
|
step5_3: "首頁 {icon} 時間軸是顯示你追蹤的帳號的貼文。"
|
||||||
step5_4: "本地 {icon} 時間線是你可以看到伺服器中所有其他用戶的貼文的時間線。"
|
step5_4: "本地 {icon} 時間軸是你可以看到伺服器中所有其他用戶的貼文的時間軸。"
|
||||||
step5_5: "社交 {icon} 時間線是你的 首頁時間線 和 本地時間線 的結合體。"
|
step5_5: "社交 {icon} 時間軸是你的 首頁時間軸 和 本地時間軸 的結合體。"
|
||||||
step5_6: "推薦 {icon} 時間線是顯示你的伺服器管理員推薦的貼文。"
|
step5_6: "推薦 {icon} 時間軸是顯示你的伺服器管理員推薦的貼文。"
|
||||||
step5_7: "全球 {icon} 時間線是顯示來自所有其他連接的伺服器的貼文。"
|
step5_7: "全球 {icon} 時間軸是顯示來自所有其他連接的伺服器的貼文。"
|
||||||
step6_1: "那麼,這裡是什麼地方?"
|
step6_1: "那麼,這裡是什麼地方?"
|
||||||
step6_2: "你不只是加入Firefish。你已經加入了Fediverse的一個門戶,這是一個由成千上萬台服務器組成的互聯網絡。"
|
step6_2: "你不只是加入Firefish。你已經加入了Fediverse的一個門戶,這是一個由成千上萬台服務器組成的互聯網絡。"
|
||||||
step6_3: "每個服務器也有不同,而並不是所有的服務器都運行Firefish。但這個服務器確實是運行Firefish的! 你可能會覺得有點複雜,但你很快就會明白的。"
|
step6_3: "每個服務器也有不同,而並不是所有的服務器都運行Firefish。但這個服務器確實是運行Firefish的! 你可能會覺得有點複雜,但你很快就會明白的。"
|
||||||
|
@ -1328,7 +1329,7 @@ _weekday:
|
||||||
_widgets:
|
_widgets:
|
||||||
memo: "備忘錄"
|
memo: "備忘錄"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
timeline: "時間線"
|
timeline: "時間軸"
|
||||||
calendar: "行事曆"
|
calendar: "行事曆"
|
||||||
trends: "發燒貼文"
|
trends: "發燒貼文"
|
||||||
clock: "時鐘"
|
clock: "時鐘"
|
||||||
|
@ -1384,9 +1385,9 @@ _poll:
|
||||||
remainingSeconds: "{s}秒後截止"
|
remainingSeconds: "{s}秒後截止"
|
||||||
_visibility:
|
_visibility:
|
||||||
public: "公開"
|
public: "公開"
|
||||||
publicDescription: "發佈至公開時間線"
|
publicDescription: "發佈至公開時間軸"
|
||||||
home: "不在主頁顯示"
|
home: "不在主頁顯示"
|
||||||
homeDescription: "僅發送至首頁的時間線"
|
homeDescription: "僅發送至首頁的時間軸"
|
||||||
followers: "追隨者"
|
followers: "追隨者"
|
||||||
followersDescription: "僅發佈至關注者"
|
followersDescription: "僅發佈至關注者"
|
||||||
specified: "指定使用者"
|
specified: "指定使用者"
|
||||||
|
@ -1787,6 +1788,7 @@ _notification:
|
||||||
renote: "轉發"
|
renote: "轉發"
|
||||||
reacted: 對您的貼文做出了反應
|
reacted: 對您的貼文做出了反應
|
||||||
renoted: 轉發了您的貼文
|
renoted: 轉發了您的貼文
|
||||||
|
voted: 投了票
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "總是顯示主欄"
|
alwaysShowMainColumn: "總是顯示主欄"
|
||||||
columnAlign: "對齊欄位"
|
columnAlign: "對齊欄位"
|
||||||
|
@ -1810,7 +1812,7 @@ _deck:
|
||||||
main: "主列"
|
main: "主列"
|
||||||
widgets: "小工具"
|
widgets: "小工具"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
tl: "時間線"
|
tl: "時間軸"
|
||||||
antenna: "天線"
|
antenna: "天線"
|
||||||
list: "清單"
|
list: "清單"
|
||||||
mentions: "提及"
|
mentions: "提及"
|
||||||
|
@ -1842,7 +1844,7 @@ accountMoved: '該使用者已遷移至新帳戶:'
|
||||||
showAds: 顯示社群橫幅
|
showAds: 顯示社群橫幅
|
||||||
noThankYou: 不用了,謝謝
|
noThankYou: 不用了,謝謝
|
||||||
selectInstance: 選擇伺服器
|
selectInstance: 選擇伺服器
|
||||||
enableRecommendedTimeline: 啟用推薦時間線
|
enableRecommendedTimeline: 啟用推薦時間軸
|
||||||
antennaInstancesDescription: 分行列出一個伺服器
|
antennaInstancesDescription: 分行列出一個伺服器
|
||||||
moveTo: 遷移此帳戶到新帳戶
|
moveTo: 遷移此帳戶到新帳戶
|
||||||
moveToLabel: '請輸入你將會遷移到的帳戶:'
|
moveToLabel: '請輸入你將會遷移到的帳戶:'
|
||||||
|
@ -1874,6 +1876,7 @@ silenced: 已靜音
|
||||||
_experiments:
|
_experiments:
|
||||||
title: 試驗功能
|
title: 試驗功能
|
||||||
enablePostImports: 啟用匯入貼文的功能
|
enablePostImports: 啟用匯入貼文的功能
|
||||||
|
postImportsCaption: 允許用戶從舊有的Firefish・Misskey・Mastodon・Akkoma・Pleroma帳號匯入貼文。在伺服器佇列堵塞時匯入貼文可能會導致載入速度變慢。
|
||||||
findOtherInstance: 找找另一個伺服器
|
findOtherInstance: 找找另一個伺服器
|
||||||
noGraze: 瀏覽器擴充元件 "Graze for Mastodon" 會與Firefish發生衝突,請停用該擴充元件。
|
noGraze: 瀏覽器擴充元件 "Graze for Mastodon" 會與Firefish發生衝突,請停用該擴充元件。
|
||||||
userSaysSomethingReasonRenote: '{name} 轉發了包含 {reason} 的貼文'
|
userSaysSomethingReasonRenote: '{name} 轉發了包含 {reason} 的貼文'
|
||||||
|
@ -1895,7 +1898,7 @@ pushNotification: 推送通知
|
||||||
subscribePushNotification: 啟用推送通知
|
subscribePushNotification: 啟用推送通知
|
||||||
unsubscribePushNotification: 停用推送通知
|
unsubscribePushNotification: 停用推送通知
|
||||||
pushNotificationAlreadySubscribed: 推送通知已經啟用
|
pushNotificationAlreadySubscribed: 推送通知已經啟用
|
||||||
recommendedInstancesDescription: 以每行分隔的推薦伺服器出現在推薦的時間線中。
|
recommendedInstancesDescription: 推薦的伺服器(將顯示在推薦時間軸中),一行一個。
|
||||||
searchPlaceholder: 在 Firefish 上搜尋
|
searchPlaceholder: 在 Firefish 上搜尋
|
||||||
cw: 內容警告
|
cw: 內容警告
|
||||||
selectChannel: 選擇一個頻道
|
selectChannel: 選擇一個頻道
|
||||||
|
@ -1903,9 +1906,9 @@ newer: 較新
|
||||||
older: 較舊
|
older: 較舊
|
||||||
jumpToPrevious: 跳到上一個
|
jumpToPrevious: 跳到上一個
|
||||||
removeReaction: 移除你的反應
|
removeReaction: 移除你的反應
|
||||||
listsDesc: 清單可以創建一個只有您指定用戶的時間線。 可以從時間線頁面訪問它們。
|
listsDesc: 清單可以創建一個只有您指定用戶的時間軸。 可以從時間軸頁面訪問它們。
|
||||||
flagSpeakAsCatDescription: 在喵咪模式下你的貼文會被喵化ヾ(•ω•`)o
|
flagSpeakAsCatDescription: 在喵咪模式下你的貼文會被喵化ヾ(•ω•`)o
|
||||||
antennasDesc: "天線會顯示符合您設置條件的新貼文!\n 可以從時間線訪問它們。"
|
antennasDesc: "天線會顯示符合您設置條件的新貼文!\n 可以從時間軸訪問它們。"
|
||||||
expandOnNoteClick: 點擊以打開貼文
|
expandOnNoteClick: 點擊以打開貼文
|
||||||
expandOnNoteClickDesc: 即使停用,您仍然可以從右鍵選單或單擊發文時間來打開貼文。
|
expandOnNoteClickDesc: 即使停用,您仍然可以從右鍵選單或單擊發文時間來打開貼文。
|
||||||
hiddenTagsDescription: '列出您希望隱藏趨勢和探索的主題標籤(不帶 #)。 隱藏的主題標籤仍然可以通過其他方式發現。'
|
hiddenTagsDescription: '列出您希望隱藏趨勢和探索的主題標籤(不帶 #)。 隱藏的主題標籤仍然可以通過其他方式發現。'
|
||||||
|
@ -1924,7 +1927,7 @@ seperateRenoteQuote: 分開轉發及引用的按鈕
|
||||||
clipsDesc: 摘錄就像一個可以分享的書籤。 你可以從每個貼文的菜單創建新摘錄或將貼文加入已有的摘錄。
|
clipsDesc: 摘錄就像一個可以分享的書籤。 你可以從每個貼文的菜單創建新摘錄或將貼文加入已有的摘錄。
|
||||||
noteId: 貼文 ID
|
noteId: 貼文 ID
|
||||||
sendModMail: 發送審核通知
|
sendModMail: 發送審核通知
|
||||||
enableIdenticonGeneration: 啟用碎片生成
|
enableIdenticonGeneration: 啟用Identicon生成
|
||||||
enableServerMachineStats: 啟用伺服器硬體統計資訊
|
enableServerMachineStats: 啟用伺服器硬體統計資訊
|
||||||
reactionPickerSkinTone: 首選表情符號膚色
|
reactionPickerSkinTone: 首選表情符號膚色
|
||||||
indexFromDescription: 留空以索引每個貼文
|
indexFromDescription: 留空以索引每個貼文
|
||||||
|
@ -1965,10 +1968,17 @@ _dialog:
|
||||||
charactersExceeded: 超過字數限制! 當前 {current} / 限制 {max}
|
charactersExceeded: 超過字數限制! 當前 {current} / 限制 {max}
|
||||||
_skinTones:
|
_skinTones:
|
||||||
yellow: 黃色
|
yellow: 黃色
|
||||||
|
medium: 中等
|
||||||
|
dark: 深色
|
||||||
|
mediumDark: 中等偏深
|
||||||
|
light: 淺色
|
||||||
|
mediumLight: 中等偏淺
|
||||||
exportZip: 匯出ZIP
|
exportZip: 匯出ZIP
|
||||||
_feeds:
|
_feeds:
|
||||||
atom: Atom
|
atom: Atom
|
||||||
rss: RSS
|
rss: RSS
|
||||||
|
copyFeed: 複製訂閱URL
|
||||||
|
jsonFeed: JSON Feed
|
||||||
emojiPackCreator: 表情包的作者
|
emojiPackCreator: 表情包的作者
|
||||||
importZip: 匯入ZIP
|
importZip: 匯入ZIP
|
||||||
delete2fa: 停用二階段認證(2FA)
|
delete2fa: 停用二階段認證(2FA)
|
||||||
|
@ -2012,3 +2022,9 @@ _iconSets:
|
||||||
regular: 標準
|
regular: 標準
|
||||||
fill: 填滿
|
fill: 填滿
|
||||||
duotone: 雙色
|
duotone: 雙色
|
||||||
|
objectStorageS3ForcePathStyleDesc: 以 "s3.amazonaws.com/<bucket>/" 而非 "<bucket>.s3.amazonaws.com"
|
||||||
|
的格式建構端點(Endpoint)URL。
|
||||||
|
indexable: 登錄至貼文搜尋引擎
|
||||||
|
origin: 來源
|
||||||
|
objectStorageS3ForcePathStyle: 使用基於路徑的端點(Endpoint)URL
|
||||||
|
clickToShowPatterns: 點擊顯示模組模式(Module Pattern)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
696d3c6255b3608a8de59fcac5aea3d08b2eeebe
|
0a44d0652244240aa50fbae3ea88c616c8e1c136
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "firefish",
|
"name": "firefish",
|
||||||
"version": "1.0.5-dev18",
|
"version": "1.0.5-dev19",
|
||||||
"codename": "aqua",
|
"codename": "aqua",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://code.naskya.net/naskya/firefish"
|
"url": "https://code.naskya.net/naskya/firefish"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.8.0",
|
"packageManager": "pnpm@8.9.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"rebuild": "pnpm run clean && pnpm run build",
|
"rebuild": "pnpm run clean && pnpm run build",
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
"gulp-replace": "1.1.4",
|
"gulp-replace": "1.1.4",
|
||||||
"gulp-terser": "2.1.0",
|
"gulp-terser": "2.1.0",
|
||||||
"install-peers": "^1.0.4",
|
"install-peers": "^1.0.4",
|
||||||
"pnpm": "8.8.0",
|
"pnpm": "8.9.2",
|
||||||
"typescript": "5.2.2"
|
"typescript": "5.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { Cache } from "./cache.js";
|
||||||
import { getWordHardMute } from "./check-word-mute.js";
|
import { getWordHardMute } from "./check-word-mute.js";
|
||||||
|
|
||||||
const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5);
|
const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5);
|
||||||
|
const mutedWordsCache = new Cache<string[][] | undefined>("mutedWords", 60 * 5);
|
||||||
|
|
||||||
export async function checkHitAntenna(
|
export async function checkHitAntenna(
|
||||||
antenna: Antenna,
|
antenna: Antenna,
|
||||||
|
@ -17,33 +18,16 @@ export async function checkHitAntenna(
|
||||||
antennaUserFollowing: User["id"][],
|
antennaUserFollowing: User["id"][],
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (note.visibility === "specified") return false;
|
if (note.visibility === "specified") return false;
|
||||||
|
if (antenna.withFile) {
|
||||||
// アンテナ作成者がノート作成者にブロックされていたらスキップ
|
if (note.fileIds && note.fileIds.length === 0) return false;
|
||||||
const blockings = await blockingCache.fetch(noteUser.id, () =>
|
}
|
||||||
Blockings.findBy({ blockerId: noteUser.id }).then((res) =>
|
if (!antenna.withReplies && note.replyId != null) return false;
|
||||||
res.map((x) => x.blockeeId),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (blockings.some((blocking) => blocking === antenna.userId)) return false;
|
|
||||||
|
|
||||||
if (
|
|
||||||
await getWordHardMute(
|
|
||||||
note,
|
|
||||||
antenna.userId,
|
|
||||||
(
|
|
||||||
await UserProfiles.findOneBy({ userId: antenna.userId })
|
|
||||||
)?.mutedWords,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (note.visibility === "followers" || note.visibility === "home") {
|
if (note.visibility === "followers" || note.visibility === "home") {
|
||||||
if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
|
if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!antenna.withReplies && note.replyId != null) return false;
|
|
||||||
|
|
||||||
if (antenna.src === "users") {
|
if (antenna.src === "users") {
|
||||||
const accts = antenna.users.map((x) => {
|
const accts = antenna.users.map((x) => {
|
||||||
const { username, host } = Acct.parse(x);
|
const { username, host } = Acct.parse(x);
|
||||||
|
@ -107,9 +91,20 @@ export async function checkHitAntenna(
|
||||||
if (matched) return false;
|
if (matched) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (antenna.withFile) {
|
// アンテナ作成者がノート作成者にブロックされていたらスキップ
|
||||||
if (note.fileIds && note.fileIds.length === 0) return false;
|
const blockings = await blockingCache.fetch(noteUser.id, () =>
|
||||||
}
|
Blockings.findBy({ blockerId: noteUser.id }).then((res) =>
|
||||||
|
res.map((x) => x.blockeeId),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (blockings.includes(antenna.userId)) return false;
|
||||||
|
|
||||||
|
const mutedWords = await mutedWordsCache.fetch(antenna.userId, () =>
|
||||||
|
UserProfiles.findOneBy({ userId: antenna.userId }).then(
|
||||||
|
(profile) => profile?.mutedWords,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (await getWordHardMute(note, antenna.userId, mutedWords)) return false;
|
||||||
|
|
||||||
// TODO: eval expression
|
// TODO: eval expression
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,7 @@ export async function getWordHardMute(
|
||||||
meId: string | null | undefined,
|
meId: string | null | undefined,
|
||||||
mutedWords?: Array<string | string[]>,
|
mutedWords?: Array<string | string[]>,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
// 自分自身
|
if (note.userId === meId || mutedWords == null) return false;
|
||||||
if (note.userId === meId || mutedWords == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutedWords.length > 0) {
|
if (mutedWords.length > 0) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -90,11 +90,25 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP-Signatureの検証
|
// HTTP-Signatureの検証
|
||||||
const httpSignatureValidated = httpSignature.verifySignature(
|
let httpSignatureValidated = httpSignature.verifySignature(
|
||||||
signature,
|
signature,
|
||||||
authUser.key.keyPem,
|
authUser.key.keyPem,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If signature validation failed, try refetching the actor
|
||||||
|
if (!httpSignatureValidated) {
|
||||||
|
authUser.key = await dbResolver.refetchPublicKeyForApId(authUser.user);
|
||||||
|
|
||||||
|
if (authUser.key == null) {
|
||||||
|
return "skip: failed to re-resolve user publicKey";
|
||||||
|
}
|
||||||
|
|
||||||
|
httpSignatureValidated = httpSignature.verifySignature(
|
||||||
|
signature,
|
||||||
|
authUser.key.keyPem,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// また、signatureのsignerは、activity.actorと一致する必要がある
|
// また、signatureのsignerは、activity.actorと一致する必要がある
|
||||||
if (!httpSignatureValidated || authUser.user.uri !== activity.actor) {
|
if (!httpSignatureValidated || authUser.user.uri !== activity.actor) {
|
||||||
// 一致しなくても、でもLD-Signatureがありそうならそっちも見る
|
// 一致しなくても、でもLD-Signatureがありそうならそっちも見る
|
||||||
|
|
|
@ -86,11 +86,25 @@ export async function checkFetch(req: IncomingMessage): Promise<number> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP-Signatureの検証
|
// HTTP-Signatureの検証
|
||||||
const httpSignatureValidated = httpSignature.verifySignature(
|
let httpSignatureValidated = httpSignature.verifySignature(
|
||||||
signature,
|
signature,
|
||||||
authUser.key.keyPem,
|
authUser.key.keyPem,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If signature validation failed, try refetching the actor
|
||||||
|
if (!httpSignatureValidated) {
|
||||||
|
authUser.key = await dbResolver.refetchPublicKeyForApId(authUser.user);
|
||||||
|
|
||||||
|
if (authUser.key == null) {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpSignatureValidated = httpSignature.verifySignature(
|
||||||
|
signature,
|
||||||
|
authUser.key.keyPem,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!httpSignatureValidated) {
|
if (!httpSignatureValidated) {
|
||||||
return 403;
|
return 403;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { Cache } from "@/misc/cache.js";
|
||||||
import { uriPersonCache, userByIdCache } from "@/services/user-cache.js";
|
import { uriPersonCache, userByIdCache } from "@/services/user-cache.js";
|
||||||
import type { IObject } from "./type.js";
|
import type { IObject } from "./type.js";
|
||||||
import { getApId } from "./type.js";
|
import { getApId } from "./type.js";
|
||||||
import { resolvePerson } from "./models/person.js";
|
import { resolvePerson, updatePerson } from "./models/person.js";
|
||||||
|
|
||||||
const publicKeyCache = new Cache<UserPublickey | null>("publicKey", 60 * 30);
|
const publicKeyCache = new Cache<UserPublickey | null>("publicKey", 60 * 30);
|
||||||
const publicKeyByUserIdCache = new Cache<UserPublickey | null>(
|
const publicKeyByUserIdCache = new Cache<UserPublickey | null>(
|
||||||
|
@ -151,7 +151,7 @@ export default class DbResolver {
|
||||||
*/
|
*/
|
||||||
public async getAuthUserFromKeyId(keyId: string): Promise<{
|
public async getAuthUserFromKeyId(keyId: string): Promise<{
|
||||||
user: CacheableRemoteUser;
|
user: CacheableRemoteUser;
|
||||||
key: UserPublickey;
|
key: UserPublickey | null;
|
||||||
} | null> {
|
} | null> {
|
||||||
const key = await publicKeyCache.fetch(
|
const key = await publicKeyCache.fetch(
|
||||||
keyId,
|
keyId,
|
||||||
|
@ -203,4 +203,15 @@ export default class DbResolver {
|
||||||
key,
|
key,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async refetchPublicKeyForApId(
|
||||||
|
user: CacheableRemoteUser,
|
||||||
|
): Promise<UserPublickey | null> {
|
||||||
|
await updatePerson(user.uri!, undefined, undefined, user);
|
||||||
|
const key = await UserPublickeys.findOneBy({ userId: user.id });
|
||||||
|
if (key != null) {
|
||||||
|
await publicKeyByUserIdCache.set(user.id, key);
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ export const meta = {
|
||||||
id: "4362f8dc-731f-4ad8-a694-be2a88922a24",
|
id: "4362f8dc-731f-4ad8-a694-be2a88922a24",
|
||||||
},
|
},
|
||||||
uriNull: {
|
uriNull: {
|
||||||
message: "User ActivityPup URI is null.",
|
message: "User ActivityPub URI is null.",
|
||||||
code: "URI_NULL",
|
code: "URI_NULL",
|
||||||
id: "bf326f31-d430-4f97-9933-5d61e4d48a23",
|
id: "bf326f31-d430-4f97-9933-5d61e4d48a23",
|
||||||
},
|
},
|
||||||
|
|
|
@ -48,12 +48,12 @@ export const meta = {
|
||||||
id: "fcd2eef9-a9b2-4c4f-8624-038099e90aa5",
|
id: "fcd2eef9-a9b2-4c4f-8624-038099e90aa5",
|
||||||
},
|
},
|
||||||
uriNull: {
|
uriNull: {
|
||||||
message: "User ActivityPup URI is null.",
|
message: "User ActivityPub URI is null.",
|
||||||
code: "URI_NULL",
|
code: "URI_NULL",
|
||||||
id: "bf326f31-d430-4f97-9933-5d61e4d48a23",
|
id: "bf326f31-d430-4f97-9933-5d61e4d48a23",
|
||||||
},
|
},
|
||||||
localUriNull: {
|
localUriNull: {
|
||||||
message: "Local User ActivityPup URI is null.",
|
message: "Local User ActivityPub URI is null.",
|
||||||
code: "URI_NULL",
|
code: "URI_NULL",
|
||||||
id: "95ba11b9-90e8-43a5-ba16-7acc1ab32e71",
|
id: "95ba11b9-90e8-43a5-ba16-7acc1ab32e71",
|
||||||
},
|
},
|
||||||
|
|
|
@ -67,9 +67,8 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
this.user &&
|
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,8 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
this.user &&
|
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -83,9 +83,8 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
this.user &&
|
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,8 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
this.user &&
|
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -81,9 +81,8 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
this.user &&
|
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as mfm from "mfm-js";
|
import * as mfm from "mfm-js";
|
||||||
import es from "../../db/elasticsearch.js";
|
import es from "@/db/elasticsearch.js";
|
||||||
import sonic from "../../db/sonic.js";
|
import sonic from "@/db/sonic.js";
|
||||||
import {
|
import {
|
||||||
publishMainStream,
|
publishMainStream,
|
||||||
publishNotesStream,
|
publishNotesStream,
|
||||||
|
|
|
@ -10,15 +10,15 @@
|
||||||
:aria-controls="bodyId"
|
:aria-controls="bodyId"
|
||||||
>
|
>
|
||||||
<template v-if="showBody"
|
<template v-if="showBody"
|
||||||
><i class="ph-caret-up ph ph-lg"></i
|
><i :class="icon('ph-caret-up')"></i
|
||||||
></template>
|
></template>
|
||||||
<template v-else
|
<template v-else
|
||||||
><i class="ph-caret-down ph ph-lg"></i
|
><i :class="icon('ph-caret-down')"></i
|
||||||
></template>
|
></template>
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
<transition
|
<transition
|
||||||
name=""
|
:name="defaultStore.state.animation ? 'folder-toggle' : ''"
|
||||||
@enter="enter"
|
@enter="enter"
|
||||||
@after-enter="afterEnter"
|
@after-enter="afterEnter"
|
||||||
@leave="leave"
|
@leave="leave"
|
||||||
|
@ -34,8 +34,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import { getUniqueId } from "@/os";
|
import { getUniqueId } from "@/os";
|
||||||
// import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
// import icon from "@/scripts/icon";
|
import icon from "@/scripts/icon";
|
||||||
|
|
||||||
const localStoragePrefix = "ui:folder:";
|
const localStoragePrefix = "ui:folder:";
|
||||||
|
|
||||||
|
@ -62,6 +62,8 @@ export default defineComponent({
|
||||||
localStoragePrefix + this.persistKey,
|
localStoragePrefix + this.persistKey,
|
||||||
) === "t"
|
) === "t"
|
||||||
: this.expanded,
|
: this.expanded,
|
||||||
|
defaultStore,
|
||||||
|
icon,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -359,7 +359,7 @@ const isDeleted = ref(false);
|
||||||
const muted = ref(
|
const muted = ref(
|
||||||
getWordSoftMute(
|
getWordSoftMute(
|
||||||
note.value,
|
note.value,
|
||||||
$i,
|
$i.id,
|
||||||
defaultStore.state.mutedWords,
|
defaultStore.state.mutedWords,
|
||||||
defaultStore.state.mutedLangs,
|
defaultStore.state.mutedLangs,
|
||||||
),
|
),
|
||||||
|
|
|
@ -234,7 +234,7 @@ const isDeleted = ref(false);
|
||||||
const muted = ref(
|
const muted = ref(
|
||||||
getWordSoftMute(
|
getWordSoftMute(
|
||||||
note.value,
|
note.value,
|
||||||
$i,
|
$i.id,
|
||||||
defaultStore.state.mutedWords,
|
defaultStore.state.mutedWords,
|
||||||
defaultStore.state.mutedLangs,
|
defaultStore.state.mutedLangs,
|
||||||
),
|
),
|
||||||
|
|
|
@ -268,7 +268,7 @@ const isDeleted = ref(false);
|
||||||
const muted = ref(
|
const muted = ref(
|
||||||
getWordSoftMute(
|
getWordSoftMute(
|
||||||
note.value,
|
note.value,
|
||||||
$i,
|
$i.id,
|
||||||
defaultStore.state.mutedWords,
|
defaultStore.state.mutedWords,
|
||||||
defaultStore.state.mutedLangs,
|
defaultStore.state.mutedLangs,
|
||||||
),
|
),
|
||||||
|
|
|
@ -509,9 +509,6 @@ useTooltip(reactionRef, (showing) => {
|
||||||
|
|
||||||
// > span:first-child {
|
// > span:first-child {
|
||||||
// opacity: 0.7;
|
// opacity: 0.7;
|
||||||
// &::after {
|
|
||||||
// content: ": ";
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
> i {
|
> i {
|
||||||
|
|
|
@ -42,11 +42,11 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const note = ref<firefish.entities.Note>();
|
const note = ref<firefish.entities.Note>();
|
||||||
const tab = ref<string>();
|
const tab = ref<string | null>(null);
|
||||||
const reactions = ref<string[]>();
|
const reactions = ref<string[]>();
|
||||||
const users = ref();
|
const users = ref();
|
||||||
|
|
||||||
watch(tab, async () => {
|
async function updateUsers(): void {
|
||||||
const res = await os.api("notes/reactions", {
|
const res = await os.api("notes/reactions", {
|
||||||
noteId: props.noteId,
|
noteId: props.noteId,
|
||||||
type: tab.value,
|
type: tab.value,
|
||||||
|
@ -54,15 +54,17 @@ watch(tab, async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
users.value = res.map((x) => x.user);
|
users.value = res.map((x) => x.user);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
watch(tab, updateUsers);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
os.api("notes/show", {
|
os.api("notes/show", {
|
||||||
noteId: props.noteId,
|
noteId: props.noteId,
|
||||||
}).then((res) => {
|
}).then(async (res) => {
|
||||||
reactions.value = Object.keys(res.reactions);
|
reactions.value = Object.keys(res.reactions);
|
||||||
tab.value = reactions.value[0];
|
|
||||||
note.value = res;
|
note.value = res;
|
||||||
|
await updateUsers();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -18,11 +18,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
import icon from "@/scripts/icon";
|
import icon from "@/scripts/icon";
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
defaultOpen: boolean;
|
defaultOpen: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const opened = ref(props.defaultOpen);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<transition name="" mode="out-in">
|
<transition
|
||||||
|
:name="defaultStore.state.animation ? 'fade' : ''"
|
||||||
|
mode="out-in"
|
||||||
|
>
|
||||||
<div v-if="pending">
|
<div v-if="pending">
|
||||||
<MkLoading />
|
<MkLoading />
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,11 +12,11 @@
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="wszdbhzo">
|
<div class="wszdbhzo">
|
||||||
<div>
|
<div>
|
||||||
<i class="ph-warning ph ph-lg"></i>
|
<i :class="iconClass('ph-warning')"></i>
|
||||||
{{ i18n.ts.somethingHappened }}
|
{{ i18n.ts.somethingHappened }}
|
||||||
</div>
|
</div>
|
||||||
<MkButton inline class="retry" @click="retry"
|
<MkButton inline class="retry" @click="retry">
|
||||||
><i class="ph-arrow-clockwise ph ph-lg"></i>
|
<i :class="iconClass('ph-arrow-clockwise')"></i>
|
||||||
{{ i18n.ts.retry }}</MkButton
|
{{ i18n.ts.retry }}</MkButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,8 +29,8 @@ import type { PropType } from "vue";
|
||||||
import { defineComponent, ref, watch } from "vue";
|
import { defineComponent, ref, watch } from "vue";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
// import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
// import icon from "@/scripts/icon";
|
import iconClass from "@/scripts/icon";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
@ -87,6 +90,8 @@ export default defineComponent({
|
||||||
result,
|
result,
|
||||||
retry,
|
retry,
|
||||||
i18n,
|
i18n,
|
||||||
|
defaultStore,
|
||||||
|
iconClass,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
primary
|
primary
|
||||||
class="save"
|
class="save"
|
||||||
@click="updated"
|
@click="updated"
|
||||||
><i class="ph-floppy-disk-back ph ph-lg"></i>
|
>
|
||||||
|
<i :class="icon('ph-floppy-disk-back')"></i>
|
||||||
{{ i18n.ts.save }}</MkButton
|
{{ i18n.ts.save }}</MkButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,6 +51,7 @@ import {
|
||||||
import { debounce } from "throttle-debounce";
|
import { debounce } from "throttle-debounce";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
import icon from "@/scripts/icon";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
@ -188,6 +190,7 @@ export default defineComponent({
|
||||||
onKeydown,
|
onKeydown,
|
||||||
updated,
|
updated,
|
||||||
i18n,
|
i18n,
|
||||||
|
icon,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
@swiper="setSwiperRef"
|
@swiper="setSwiperRef"
|
||||||
@slide-change="onSlideChange"
|
@slide-change="onSlideChange"
|
||||||
>
|
>
|
||||||
<swiper-slide>
|
<swiper-slide v-if="true">
|
||||||
<MkFolder class="_gap">
|
<MkFolder class="_gap">
|
||||||
<template #header
|
<template #header
|
||||||
><i :class="icon('ph-clock')"></i>
|
><i :class="icon('ph-clock')"></i>
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
<swiper-slide>
|
<swiper-slide v-if="true">
|
||||||
<MkPagination
|
<MkPagination
|
||||||
v-slot="{ items }"
|
v-slot="{ items }"
|
||||||
:pagination="likedPostsPagination"
|
:pagination="likedPostsPagination"
|
||||||
|
@ -81,7 +81,7 @@
|
||||||
</div>
|
</div>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
<swiper-slide>
|
<swiper-slide v-if="true">
|
||||||
<MkA to="/gallery/new" class="_link" style="margin: 16px"
|
<MkA to="/gallery/new" class="_link" style="margin: 16px"
|
||||||
><i :class="icon('ph-plus')"></i>
|
><i :class="icon('ph-plus')"></i>
|
||||||
{{ i18n.ts.postToGallery }}</MkA
|
{{ i18n.ts.postToGallery }}</MkA
|
||||||
|
|
|
@ -75,6 +75,7 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
showBody: this.expanded,
|
showBody: this.expanded,
|
||||||
i18n,
|
i18n,
|
||||||
|
icon,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
>
|
>
|
||||||
<template #func>
|
<template #func>
|
||||||
<button class="_button" @click="changeType()">
|
<button class="_button" @click="changeType()">
|
||||||
<i :class="icon('ph-pencil')"></i>
|
<i :class="iconClass('ph-pencil')"></i>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ import * as os from "@/os";
|
||||||
import { isLiteralValue } from "@/scripts/hpml/expr";
|
import { isLiteralValue } from "@/scripts/hpml/expr";
|
||||||
import { funcDefs } from "@/scripts/hpml/lib";
|
import { funcDefs } from "@/scripts/hpml/lib";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import icon from "@/scripts/icon";
|
import iconClass from "@/scripts/icon";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
@ -207,6 +207,7 @@ export default defineComponent({
|
||||||
warn: null,
|
warn: null,
|
||||||
slots: "",
|
slots: "",
|
||||||
i18n,
|
i18n,
|
||||||
|
iconClass,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
@swiper="setSwiperRef"
|
@swiper="setSwiperRef"
|
||||||
@slide-change="onSlideChange"
|
@slide-change="onSlideChange"
|
||||||
>
|
>
|
||||||
<swiper-slide>
|
<swiper-slide v-if="true">
|
||||||
<div class="rknalgpo">
|
<div class="rknalgpo">
|
||||||
<MkPagination
|
<MkPagination
|
||||||
v-slot="{ items }"
|
v-slot="{ items }"
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
<swiper-slide>
|
<swiper-slide v-if="true">
|
||||||
<div class="rknalgpo liked">
|
<div class="rknalgpo liked">
|
||||||
<MkPagination
|
<MkPagination
|
||||||
v-slot="{ items }"
|
v-slot="{ items }"
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
<swiper-slide>
|
<swiper-slide v-if="true">
|
||||||
<div class="rknalgpo my">
|
<div class="rknalgpo my">
|
||||||
<div class="buttoncontainer">
|
<div class="buttoncontainer">
|
||||||
<MkButton class="new primary" @click="create()"
|
<MkButton class="new primary" @click="create()"
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import type * as firefish from "firefish-js";
|
||||||
|
|
||||||
export interface Muted {
|
export interface Muted {
|
||||||
muted: boolean;
|
muted: boolean;
|
||||||
matched: string[];
|
matched: string[];
|
||||||
|
@ -7,7 +9,7 @@ export interface Muted {
|
||||||
const NotMuted = { muted: false, matched: [] };
|
const NotMuted = { muted: false, matched: [] };
|
||||||
|
|
||||||
function checkLangMute(
|
function checkLangMute(
|
||||||
note: NoteLike,
|
note: firefish.entities.Note,
|
||||||
mutedLangs: Array<string | string[]>,
|
mutedLangs: Array<string | string[]>,
|
||||||
): Muted {
|
): Muted {
|
||||||
const mutedLangList = new Set(
|
const mutedLangList = new Set(
|
||||||
|
@ -20,7 +22,7 @@ function checkLangMute(
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkWordMute(
|
function checkWordMute(
|
||||||
note: NoteLike,
|
note: firefish.entities.Note,
|
||||||
mutedWords: Array<string | string[]>,
|
mutedWords: Array<string | string[]>,
|
||||||
): Muted {
|
): Muted {
|
||||||
let text = `${note.cw ?? ""} ${note.text ?? ""}`;
|
let text = `${note.cw ?? ""} ${note.text ?? ""}`;
|
||||||
|
@ -72,15 +74,12 @@ function checkWordMute(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWordSoftMute(
|
export function getWordSoftMute(
|
||||||
note: Record<string, any>,
|
note: firefish.entities.Note,
|
||||||
me: Record<string, any> | null | undefined,
|
meId: string | null | undefined,
|
||||||
mutedWords: Array<string | string[]>,
|
mutedWords: Array<string | string[]>,
|
||||||
mutedLangs: Array<string | string[]>,
|
mutedLangs: Array<string | string[]>,
|
||||||
): Muted {
|
): Muted {
|
||||||
// 自分自身
|
if (note.userId === meId) return NotMuted;
|
||||||
if (me && note.userId === me.id) {
|
|
||||||
return NotMuted;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutedWords.length > 0) {
|
if (mutedWords.length > 0) {
|
||||||
const noteMuted = checkWordMute(note, mutedWords);
|
const noteMuted = checkWordMute(note, mutedWords);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
|
||||||
export default function icon(name: string, large = true): string {
|
export default function (name: string, large = true): string {
|
||||||
return `${name} ${large ? "ph-lg" : ""} ${defaultStore.state.iconSet}`;
|
return `${name} ${large ? "ph-lg" : ""} ${defaultStore.state.iconSet}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as mfm from "mfm-js";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
import { expandKaTeXMacro } from "@/scripts/katex-macro";
|
import { expandKaTeXMacro } from "@/scripts/katex-macro";
|
||||||
|
|
||||||
export default function preprocess(text: string): string {
|
export default function (text: string): string {
|
||||||
if (defaultStore.state.enableCustomKaTeXMacro) {
|
if (defaultStore.state.enableCustomKaTeXMacro) {
|
||||||
const parsedKaTeXMacro =
|
const parsedKaTeXMacro =
|
||||||
localStorage.getItem("customKaTeXMacroParsed") ?? "{}";
|
localStorage.getItem("customKaTeXMacroParsed") ?? "{}";
|
||||||
|
|
|
@ -41,23 +41,23 @@ export const defaultStore = markRaw(
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
tlHomeHintClosed: {
|
tlHomeHintClosed: {
|
||||||
where: "device",
|
where: "account",
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
tlLocalHintClosed: {
|
tlLocalHintClosed: {
|
||||||
where: "device",
|
where: "account",
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
tlRecommendedHintClosed: {
|
tlRecommendedHintClosed: {
|
||||||
where: "device",
|
where: "account",
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
tlSocialHintClosed: {
|
tlSocialHintClosed: {
|
||||||
where: "device",
|
where: "account",
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
tlGlobalHintClosed: {
|
tlGlobalHintClosed: {
|
||||||
where: "device",
|
where: "account",
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
keepCw: {
|
keepCw: {
|
||||||
|
|
|
@ -127,7 +127,9 @@
|
||||||
class="item _button help"
|
class="item _button help"
|
||||||
@click="openHelpMenu"
|
@click="openHelpMenu"
|
||||||
>
|
>
|
||||||
<i :class="icon('ph-info ph-xl ph-fw help', false)"></i>
|
<i
|
||||||
|
:class="icon('ph-info help icon ph-xl ph-fw', false)"
|
||||||
|
></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"api": "pnpm api-extractor run --local --verbose",
|
"api": "pnpm api-extractor run --local --verbose",
|
||||||
"api-prod": "pnpm api-extractor run --verbose",
|
"api-prod": "pnpm api-extractor run --verbose",
|
||||||
"api-doc": "pnpm api-documenter markdown -i ./etc/",
|
"api-doc": "pnpm api-documenter markdown -i ./etc/",
|
||||||
"lint": "pnpm biome check --apply **/*.ts",
|
"lint": "pnpm biome check --apply *.ts",
|
||||||
"format": "pnpm biome format --write **/*.ts"
|
"format": "pnpm biome format --write **/*.ts"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"build": "pnpm vite build --emptyOutDir",
|
"build": "pnpm vite build --emptyOutDir",
|
||||||
"build:debug": "pnpm run build",
|
"build:debug": "pnpm run build",
|
||||||
"watch": "pnpm swc src -d built -D -w",
|
"watch": "pnpm swc src -d built -D -w",
|
||||||
"lint": "pnpm biome check **/*.ts --apply",
|
"lint": "pnpm biome check *.ts --apply",
|
||||||
"format": "pnpm biome format * --write"
|
"format": "pnpm biome format * --write"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
1048
pnpm-lock.yaml
1048
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue