Merge branch 'develop' into import-masto-package

This commit is contained in:
コルセット姫@がんばらない 2023-07-17 09:47:04 +00:00
commit cb3b7ef5be
36 changed files with 279 additions and 55 deletions

3
.gitignore vendored
View file

@ -27,7 +27,7 @@ coverage
!/.config/helm_values_example.yml !/.config/helm_values_example.yml
!/.config/LICENSE !/.config/LICENSE
#docker dev config # docker dev config
/dev/docker-compose.yml /dev/docker-compose.yml
# misskey # misskey
@ -46,6 +46,7 @@ files
ormconfig.json ormconfig.json
packages/backend/assets/instance.css packages/backend/assets/instance.css
packages/backend/assets/sounds/None.mp3 packages/backend/assets/sounds/None.mp3
packages/backend/assets/LICENSE
!packages/backend/src/db !packages/backend/src/db

View file

@ -16,7 +16,6 @@
## Work in progress ## Work in progress
- Link verification
- Better Messaging UI - Better Messaging UI
- Better API Documentation - Better API Documentation
- Remote follow button - Remote follow button
@ -118,6 +117,7 @@
- Non-mangled unicode emojis - Non-mangled unicode emojis
- Skin tone selection support - Skin tone selection support
- [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative - [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative
- Link verification
## Implemented (remote) ## Implemented (remote)

View file

@ -1179,7 +1179,6 @@ _profile:
youCanIncludeHashtags: "يمكنك أيضًا إضافة وسوم إلى سيرتك التعريفية." youCanIncludeHashtags: "يمكنك أيضًا إضافة وسوم إلى سيرتك التعريفية."
metadata: "معلومات إضافية" metadata: "معلومات إضافية"
metadataEdit: "عدّل المعلومات الإضافية" metadataEdit: "عدّل المعلومات الإضافية"
metadataDescription: "يُمكنك عرض 4 حقول معلومات في ملفك الشخصي"
metadataLabel: "التسمية" metadataLabel: "التسمية"
metadataContent: "المحتوى" metadataContent: "المحتوى"
changeAvatar: "غيّر الصورة الرمزية" changeAvatar: "غيّر الصورة الرمزية"

View file

@ -1268,7 +1268,7 @@ _profile:
youCanIncludeHashtags: "হ্যাশট্যাগ অন্তর্ভুক্ত করা যেতে পারে।" youCanIncludeHashtags: "হ্যাশট্যাগ অন্তর্ভুক্ত করা যেতে পারে।"
metadata: "অতিরিক্ত তথ্য" metadata: "অতিরিক্ত তথ্য"
metadataEdit: "অতিরিক্ত তথ্য সম্পাদনা করুন" metadataEdit: "অতিরিক্ত তথ্য সম্পাদনা করুন"
metadataDescription: "আপনি আপনার প্রোফাইলে একটি টেবিল হিসাবে চারটি অতিরিক্ত তথ্য দেখাতে পারেন।" metadataDescription: "আপনি আপনার প্রোফাইলে একটি টেবিল হিসাবে চারটি অতিরিক্ত তথ্য দেখাতে পারেন।. আপনি আপনার প্রোফাইলে লিঙ্কটি যাচাই করতে {rel} এর সাথে একটি {a} ট্যাগ বা {l} ট্যাগ যোগ করতে পারেন!"
metadataLabel: "লেবেল" metadataLabel: "লেবেল"
metadataContent: "বিষয়বস্তু" metadataContent: "বিষয়বস্তু"
changeAvatar: "অ্যাভাটার পরিবর্তন করুন" changeAvatar: "অ্যাভাটার পরিবর্তন করুন"

View file

@ -409,8 +409,9 @@ _profile:
locationDescription: Si primer introduïu la vostra ciutat, es mostrarà l'hora local locationDescription: Si primer introduïu la vostra ciutat, es mostrarà l'hora local
a altres usuaris. a altres usuaris.
name: Nom name: Nom
metadataDescription: Fent servir això, podràs mostrar camps d'informació addicionals metadataDescription: "Fent servir això, podràs mostrar camps d'informació addicionals
al vostre perfil. al vostre perfil. Podeu afegir una etiqueta {a} o una etiqueta {l} amb {rel} per
verificar l'enllaç al vostre perfil."
_exportOrImport: _exportOrImport:
followingList: "Usuaris que segueixes" followingList: "Usuaris que segueixes"
muteList: "Silencia" muteList: "Silencia"
@ -2161,3 +2162,4 @@ remindMeLater: Potser després
removeMember: Elimina el membre removeMember: Elimina el membre
removeQuote: Elimina la cita removeQuote: Elimina la cita
removeRecipient: Elimina el destinatari removeRecipient: Elimina el destinatari
verifiedLink: Enllaç verificat

View file

@ -1551,7 +1551,7 @@ _profile:
metadata: "Zusätzliche Informationen" metadata: "Zusätzliche Informationen"
metadataEdit: "Zusätzliche Informationen bearbeiten" metadataEdit: "Zusätzliche Informationen bearbeiten"
metadataDescription: "Hierdurch kannst du auf deinem Profil zusätzliche Informationsblöcke metadataDescription: "Hierdurch kannst du auf deinem Profil zusätzliche Informationsblöcke
anzeigen lassen." anzeigen lassen. Sie können ein {a}-Tag oder ein {l}-Tag mit {rel} hinzufügen, um den Link in Ihrem Profil zu überprüfen!"
metadataLabel: "Beschriftung" metadataLabel: "Beschriftung"
metadataContent: "Inhalt" metadataContent: "Inhalt"
changeAvatar: "Profilbild ändern" changeAvatar: "Profilbild ändern"

View file

@ -1124,6 +1124,7 @@ remindMeLater: "Maybe later"
removeQuote: "Remove quote" removeQuote: "Remove quote"
removeRecipient: "Remove recipient" removeRecipient: "Remove recipient"
removeMember: "Remove member" removeMember: "Remove member"
verifiedLink: "Verified link"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "Reduces the effort of server moderation through automatically recognizing description: "Reduces the effort of server moderation through automatically recognizing
@ -1676,8 +1677,10 @@ _profile:
youCanIncludeHashtags: "You can also include hashtags in your bio." youCanIncludeHashtags: "You can also include hashtags in your bio."
metadata: "Additional Information" metadata: "Additional Information"
metadataEdit: "Edit additional Information" metadataEdit: "Edit additional Information"
metadataDescription: "Using these, you can display additional information fields metadataDescription:
in your profile." "Using these, you can display additional information fields
in your profile. You can add an {a} tag or {l} tag with {rel}
to verify the link on your profile!"
metadataLabel: "Label" metadataLabel: "Label"
metadataContent: "Content" metadataContent: "Content"
changeAvatar: "Change avatar" changeAvatar: "Change avatar"

View file

@ -1475,7 +1475,7 @@ _profile:
youCanIncludeHashtags: "Puedes añadir hashtags" youCanIncludeHashtags: "Puedes añadir hashtags"
metadata: "información adicional" metadata: "información adicional"
metadataEdit: "Editar información adicional" metadataEdit: "Editar información adicional"
metadataDescription: "Muestra la información adicional en el perfil" metadataDescription: "Muestra la información adicional en el perfil. ¡Puede agregar una etiqueta {a} o una etiqueta {l} con {rel} para verificar el enlace en su perfil!"
metadataLabel: "Etiqueta" metadataLabel: "Etiqueta"
metadataContent: "Contenido" metadataContent: "Contenido"
changeAvatar: "Cambiar avatar" changeAvatar: "Cambiar avatar"

View file

@ -1413,7 +1413,7 @@ _profile:
metadata: "Informations supplémentaires" metadata: "Informations supplémentaires"
metadataEdit: "Éditer les informations supplémentaires" metadataEdit: "Éditer les informations supplémentaires"
metadataDescription: "Vous pouvez afficher jusqu'à quatre informations supplémentaires metadataDescription: "Vous pouvez afficher jusqu'à quatre informations supplémentaires
dans votre profil." dans votre profil. Vous pouvez ajouter une balise {a} ou une balise {l} avec {rel} pour vérifier le lien sur votre profil!"
metadataLabel: "Étiquette" metadataLabel: "Étiquette"
metadataContent: "Contenu" metadataContent: "Contenu"
changeAvatar: "Changer l'image de profil" changeAvatar: "Changer l'image de profil"

View file

@ -1399,7 +1399,7 @@ _profile:
metadata: "Informasi tambahan" metadata: "Informasi tambahan"
metadataEdit: "Sunting informasi tambahan" metadataEdit: "Sunting informasi tambahan"
metadataDescription: "Kamu dapat menampilkan hingga 4 bagian informasi tambahan\ metadataDescription: "Kamu dapat menampilkan hingga 4 bagian informasi tambahan\
\ ke dalam profilmu." \ ke dalam profilmu. Anda dapat menambahkan tag {a} atau tag {l} dengan {rel} untuk memverifikasi tautan di profil Anda!"
metadataLabel: "Label" metadataLabel: "Label"
metadataContent: "Isi" metadataContent: "Isi"
changeAvatar: "Ubah avatar" changeAvatar: "Ubah avatar"

View file

@ -1266,7 +1266,7 @@ _profile:
metadata: "Informazioni aggiuntive" metadata: "Informazioni aggiuntive"
metadataEdit: "Modifica informazioni aggiuntive" metadataEdit: "Modifica informazioni aggiuntive"
metadataDescription: "Puoi pubblicare fino a quattro informazioni aggiuntive sul metadataDescription: "Puoi pubblicare fino a quattro informazioni aggiuntive sul
profilo." profilo. Puoi aggiungere un tag {a} o {l} con {rel} per verificare il link sul tuo profilo!"
metadataLabel: "Etichetta" metadataLabel: "Etichetta"
metadataContent: "Contenuto" metadataContent: "Contenuto"
changeAvatar: "Modifica immagine profilo" changeAvatar: "Modifica immagine profilo"

View file

@ -1491,7 +1491,7 @@ _profile:
youCanIncludeHashtags: "ハッシュタグを含められます。" youCanIncludeHashtags: "ハッシュタグを含められます。"
metadata: "追加情報" metadata: "追加情報"
metadataEdit: "追加情報を編集" metadataEdit: "追加情報を編集"
metadataDescription: "プロフィールに表として追加情報を表示できます。" metadataDescription: "プロフィールに表として追加情報を表示できます。{a}タグまたは{l}タグを{rel}とともに追加すると、プロフィールのリンクを確認できます。"
metadataLabel: "ラベル" metadataLabel: "ラベル"
metadataContent: "内容" metadataContent: "内容"
changeAvatar: "アバター画像を変更" changeAvatar: "アバター画像を変更"

View file

@ -1319,7 +1319,7 @@ _profile:
youCanIncludeHashtags: "해시 태그를 포함할 수 있습니다." youCanIncludeHashtags: "해시 태그를 포함할 수 있습니다."
metadata: "추가 정보" metadata: "추가 정보"
metadataEdit: "추가 정보 편집" metadataEdit: "추가 정보 편집"
metadataDescription: "프로필에 추가 정보를 표시할 수 있어요" metadataDescription: "프로필에 추가 정보를 표시할 수 있어요. {rel}과 함께 {a} 태그 또는 {l} 태그를 추가하여 프로필의 링크를 확인할 수 있습니다!"
metadataLabel: "라벨" metadataLabel: "라벨"
metadataContent: "내용" metadataContent: "내용"
changeAvatar: "아바타 이미지 변경" changeAvatar: "아바타 이미지 변경"

View file

@ -1404,7 +1404,7 @@ _profile:
metadata: "Dodatkowe informacje" metadata: "Dodatkowe informacje"
metadataEdit: "Edytuj dodatkowe informacje" metadataEdit: "Edytuj dodatkowe informacje"
metadataDescription: "Możesz wyświetlać do czterech sekcji dodatkowych informacji metadataDescription: "Możesz wyświetlać do czterech sekcji dodatkowych informacji
na swoim profilu." na swoim profilu. Możesz dodać tag {a} lub tag {l} z {rel}, aby zweryfikować link w swoim profilu!"
metadataLabel: "Etykieta" metadataLabel: "Etykieta"
metadataContent: "Treść" metadataContent: "Treść"
changeAvatar: "Zmień awatar" changeAvatar: "Zmień awatar"

View file

@ -1398,7 +1398,7 @@ _profile:
youCanIncludeHashtags: "Можете использовать здесь хэштеги." youCanIncludeHashtags: "Можете использовать здесь хэштеги."
metadata: "Дополнительные сведения" metadata: "Дополнительные сведения"
metadataEdit: "Редактировать дополнительные сведения" metadataEdit: "Редактировать дополнительные сведения"
metadataDescription: "Можно добавить до четырёх дополнительных граф в профиль." metadataDescription: "Можно добавить до четырёх дополнительных граф в профиль. Вы можете добавить тег {a} или тег {l} с {rel}, чтобы подтвердить ссылку в своем профиле!"
metadataLabel: "Метка" metadataLabel: "Метка"
metadataContent: "Содержимое" metadataContent: "Содержимое"
changeAvatar: "Поменять аватар" changeAvatar: "Поменять аватар"

View file

@ -1337,7 +1337,7 @@ _profile:
youCanIncludeHashtags: "Vo svojom bio môžete mať aj hashtagy." youCanIncludeHashtags: "Vo svojom bio môžete mať aj hashtagy."
metadata: "Dodatočné informácie" metadata: "Dodatočné informácie"
metadataEdit: "Upraviť dodatočné informácie" metadataEdit: "Upraviť dodatočné informácie"
metadataDescription: "Vo svojom profile môžete uviesť až štyri dodatočné informačné polia." metadataDescription: "Vo svojom profile môžete uviesť až štyri dodatočné informačné polia. Dodate lahko oznako {a} ali oznako {l} z {rel}, da preverite povezavo v svojem profile!"
metadataLabel: "Popisok" metadataLabel: "Popisok"
metadataContent: "Obsah" metadataContent: "Obsah"
changeAvatar: "Zmeniť avatara" changeAvatar: "Zmeniť avatara"

View file

@ -182,7 +182,7 @@ _profile:
gösterecektir. gösterecektir.
youCanIncludeHashtags: Hakkımdan'da etiket kullanabilirsin. youCanIncludeHashtags: Hakkımdan'da etiket kullanabilirsin.
description: Hakkımda description: Hakkımda
metadataDescription: Bunları kullanarak profilinizde ek bilgi alanları görüntüleyebilirsiniz. metadataDescription: 'Bunları kullanarak profilinizde ek bilgi alanları görüntüleyebilirsiniz. Profilinizdeki bağlantıyı doğrulamak için {rel} ile bir {a} etiketi veya {l} etiketi ekleyebilirsiniz!'
metadata: Ek Bilgi metadata: Ek Bilgi
metadataContent: İçerik metadataContent: İçerik
metadataLabel: Etiket metadataLabel: Etiket

View file

@ -155,7 +155,7 @@ flagAsBotDescription: "Ввімкніть якщо цей обліковий з
flagAsCat: "Акаунт кота" flagAsCat: "Акаунт кота"
flagAsCatDescription: "Ввімкніть, щоб позначити, що обліковий запис є котиком, та flagAsCatDescription: "Ввімкніть, щоб позначити, що обліковий запис є котиком, та
отримати котячі вуха!" отримати котячі вуха!"
flagShowTimelineReplies: "Показувати відповіді на нотатки на часовій шкалі" flagShowTimelineReplies: "Показувати відповіді на записи в стрічці"
flagShowTimelineRepliesDescription: "Показує відповіді користувачів на записи інших flagShowTimelineRepliesDescription: "Показує відповіді користувачів на записи інших
користувачів у стрічці." користувачів у стрічці."
autoAcceptFollowed: "Автоматично приймати запити на підписку від користувачів, на autoAcceptFollowed: "Автоматично приймати запити на підписку від користувачів, на
@ -1250,7 +1250,7 @@ _poll:
_visibility: _visibility:
public: "Публічний" public: "Публічний"
publicDescription: "Ваш запис буде видно в усіх публічних стрічках" publicDescription: "Ваш запис буде видно в усіх публічних стрічках"
home: "Скритий" home: "Домашній"
homeDescription: "Лише на домашній стрічці" homeDescription: "Лише на домашній стрічці"
followers: "Підписники" followers: "Підписники"
followersDescription: "Зробити видимим тільки для ваших підписників і згаданих користувачів" followersDescription: "Зробити видимим тільки для ваших підписників і згаданих користувачів"
@ -1277,7 +1277,8 @@ _profile:
metadata: "Додаткова інформація" metadata: "Додаткова інформація"
metadataEdit: "Редагувати додаткову інформацію" metadataEdit: "Редагувати додаткову інформацію"
metadataDescription: "Ви можете вказати до чотирьох пунктів додаткової інформації metadataDescription: "Ви можете вказати до чотирьох пунктів додаткової інформації
у своєму профілі." у своєму профілі. Ви можете додати тег {a} або {l} за допомогою {rel}, щоб підтвердити
посилання у своєму профілі!"
metadataLabel: "Назва" metadataLabel: "Назва"
metadataContent: "Вміст" metadataContent: "Вміст"
changeAvatar: "Змінити аватар" changeAvatar: "Змінити аватар"
@ -2131,3 +2132,4 @@ customSplashIconsDescription: URL-адреси іконок для застав
які будуть показуватися випадковим чином щоразу, коли користувач завантажує/перезавантажує які будуть показуватися випадковим чином щоразу, коли користувач завантажує/перезавантажує
сторінку. Будь ласка, переконайтеся, що зображення знаходяться на статичній URL-адресі, сторінку. Будь ласка, переконайтеся, що зображення знаходяться на статичній URL-адресі,
бажано, щоб вони були змінені до розміру 192x192. бажано, щоб вони були змінені до розміру 192x192.
verifiedLink: Перевірене посилання

View file

@ -1342,7 +1342,7 @@ _profile:
youCanIncludeHashtags: "Bạn có thể dùng hashtag trong tiểu sử." youCanIncludeHashtags: "Bạn có thể dùng hashtag trong tiểu sử."
metadata: "Thông tin bổ sung" metadata: "Thông tin bổ sung"
metadataEdit: "Sửa thông tin bổ sung" metadataEdit: "Sửa thông tin bổ sung"
metadataDescription: "Sử dụng phần này, bạn có thể hiển thị các mục thông tin bổ sung trong hồ sơ của mình." metadataDescription: "Sử dụng phần này, bạn có thể hiển thị các mục thông tin bổ sung trong hồ sơ của mình. Bạn có thể thêm thẻ {a} hoặc thẻ {l} với {rel} để xác minh liên kết trên tiểu sử của mình!"
metadataLabel: "Nhãn" metadataLabel: "Nhãn"
metadataContent: "Nội dung" metadataContent: "Nội dung"
changeAvatar: "Đổi ảnh đại diện" changeAvatar: "Đổi ảnh đại diện"

View file

@ -1402,7 +1402,7 @@ _profile:
youCanIncludeHashtags: "您可以包含一个话题标签。" youCanIncludeHashtags: "您可以包含一个话题标签。"
metadata: "附加信息" metadata: "附加信息"
metadataEdit: "附加信息编辑" metadataEdit: "附加信息编辑"
metadataDescription: "使用这些,您可以在您的个人资料中显示其它信息字段。" metadataDescription: "使用这些,您可以在您的个人资料中显示其它信息字段。您可以添加带有 {rel} 的 {a} 标签或 {l} 标签来验证您个人资料上的链接!"
metadataLabel: "标签" metadataLabel: "标签"
metadataContent: "内容" metadataContent: "内容"
changeAvatar: "修改头像" changeAvatar: "修改头像"

View file

@ -984,6 +984,12 @@ _aboutMisskey:
donate: "贊助Calckey" donate: "贊助Calckey"
morePatrons: "還有許許多多幫助我們的其他人,非常感謝你們。 🥰" morePatrons: "還有許許多多幫助我們的其他人,非常感謝你們。 🥰"
patrons: "贊助者" patrons: "贊助者"
patronsList: 按時間順序列出,而不是按贊助規模列出。使用上面的連結贊助,在這裡獲得顯示您名字的機會!
sponsors: Calckey 贊助者們
donateTitle: 覺得 Calckey 棒嗎?
pleaseDonateToCalckey: 請考慮向 Calckey 贊助以支持其發展。
pleaseDonateToHost: 還請考慮捐贈給您在使用的伺服器 {host},以支援龐大的運營成本。
donateHost: 贊助給 {host}
_nsfw: _nsfw:
respect: "隱藏敏感內容" respect: "隱藏敏感內容"
ignore: "不隱藏敏感內容" ignore: "不隱藏敏感內容"
@ -1060,6 +1066,8 @@ _mfm:
position: 位置 position: 位置
alwaysPlay: 自動播放所有MFM動畫 alwaysPlay: 自動播放所有MFM動畫
positionDescription: 按指定數量移動內容。 positionDescription: 按指定數量移動內容。
advancedDescription: 如果禁用,則僅允許基本標記,除非正在播放 MFM 動畫
advanced: 高級MFM
_instanceTicker: _instanceTicker:
none: "隱藏" none: "隱藏"
remote: "向遠端使用者顯示" remote: "向遠端使用者顯示"
@ -1202,14 +1210,14 @@ _tutorial:
step1_1: "歡迎!" step1_1: "歡迎!"
step1_2: "讓我們把你安排好。你很快就會啟動並運行!" step1_2: "讓我們把你安排好。你很快就會啟動並運行!"
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} 時間線是顯示你的伺服器管理員推薦的貼文。"
@ -1361,7 +1369,7 @@ _profile:
youCanIncludeHashtags: "你也可以在「關於我」中加上 #tag。" youCanIncludeHashtags: "你也可以在「關於我」中加上 #tag。"
metadata: "進階資訊" metadata: "進階資訊"
metadataEdit: "編輯進階資訊" metadataEdit: "編輯進階資訊"
metadataDescription: "可以在個人資料中以表格形式顯示其他資訊。" metadataDescription: "可以在個人資料中以表格形式顯示其他資訊。您可以添加帶有 {rel} 的 {a} 標籤或 {l} 標籤來驗證您個人資料上的鏈接!"
metadataLabel: "標籤" metadataLabel: "標籤"
metadataContent: "内容" metadataContent: "内容"
changeAvatar: "更換大頭貼" changeAvatar: "更換大頭貼"
@ -1820,12 +1828,12 @@ _experiments:
title: 試驗功能 title: 試驗功能
findOtherInstance: 找找另一個伺服器 findOtherInstance: 找找另一個伺服器
noGraze: 瀏覽器擴展 "Graze for Mastodon" 會與Calckey發生衝突請停用該擴展。 noGraze: 瀏覽器擴展 "Graze for Mastodon" 會與Calckey發生衝突請停用該擴展。
userSaysSomethingReasonRenote: '{name} 轉傳了包含 {reason} 的帖子' userSaysSomethingReasonRenote: '{name} 轉傳了包含 {reason} 的貼文'
pushNotificationNotSupported: 你的瀏覽器或伺服器不支援推送通知 pushNotificationNotSupported: 你的瀏覽器或伺服器不支援推送通知
accessibility: 輔助功能 accessibility: 輔助功能
userSaysSomethingReasonReply: '{name} 回復了包含 {reason} 的帖子' userSaysSomethingReasonReply: '{name} 回覆了包含 {reason} 的貼文'
hiddenTags: 隱藏主題標籤 hiddenTags: 隱藏主題標籤
indexPosts: 索引帖子 indexPosts: 索引貼文
indexNotice: 現在開始索引。 這可能需要一段時間,請不要在一個小時內重啟你的伺服器。 indexNotice: 現在開始索引。 這可能需要一段時間,請不要在一個小時內重啟你的伺服器。
deleted: 已刪除 deleted: 已刪除
editNote: 編輯筆記 editNote: 編輯筆記
@ -1861,9 +1869,33 @@ audio: 音訊
sendPushNotificationReadMessageCaption: 包含文本 “{emptyPushNotificationMessage}” 的通知將顯示一小段時間。 sendPushNotificationReadMessageCaption: 包含文本 “{emptyPushNotificationMessage}” 的通知將顯示一小段時間。
這可能會增加您設備的電池使用量(如果適用)。 這可能會增加您設備的電池使用量(如果適用)。
channelFederationWarn: 頻道功能尚未與聯邦宇宙連動 channelFederationWarn: 頻道功能尚未與聯邦宇宙連動
swipeOnMobile: 允許在頁面之間滑動 swipeOnMobile: 允許以滑動在頁面之間切換
sendPushNotificationReadMessage: 閱讀相關通知或消息後刪除推送通知 sendPushNotificationReadMessage: 閱讀相關通知或消息後刪除推送通知
image: 圖片 image: 圖片
seperateRenoteQuote: 分別獨立的轉傳及引用按鈕 seperateRenoteQuote: 分別獨立的轉傳及引用按鈕
clipsDesc: 摘錄就像一個可以分享的書籤。 你可以從每個貼文的菜單創建新摘錄或將貼文加入已有的摘錄。 clipsDesc: 摘錄就像一個可以分享的書籤。 你可以從每個貼文的菜單創建新摘錄或將貼文加入已有的摘錄。
noteId: 貼文 ID noteId: 貼文 ID
sendModMail: 發送審核通知
enableIdenticonGeneration: 啟用碎片生成
enableServerMachineStats: 啟用伺服器硬體統計資訊
reactionPickerSkinTone: 首選表情符號膚色
indexFromDescription: 留空以索引每個貼文
preventAiLearning: 防止 AI 機器人抓取
preventAiLearningDescription: 請求第三方 AI 語言模型不要研究您上傳的內容,例如貼文和圖像。
indexFrom: 從貼文 ID 開始的索引
isLocked: 該帳戶已獲得以下批准
isModerator: 板主
isAdmin: 管理員
isPatron: Calckey 項目贊助者
silencedWarning: 顯示此頁面是因為這些使用者來自您伺服器管理員已靜音的伺服器,因此他們可能是垃圾訊息。
signupsDisabled: 該伺服器上的註冊當前已被禁用,但您隨時可以在另一台伺服器上註冊!或是您有該伺服器的邀請碼,請在下面輸入。
showPopup: 通過彈出式視窗通知用戶
showWithSparkles: 閃閃發光的顯示
youHaveUnreadAnnouncements: 您有未讀的公告
donationLink: 連結到贊助頁面
neverShow: 不再顯示
remindMeLater: 可能之後
removeQuote: 删除引用
removeRecipient: 刪除收件者
removeMember: 刪除成員
isBot: 此帳戶是機器人

View file

@ -0,0 +1,13 @@
Copyright 2023 Calckey
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -51,6 +51,7 @@ export class UserProfile {
public fields: { public fields: {
name: string; name: string;
value: string; value: string;
verified?: boolean;
}[]; }[];
@Column("varchar", { @Column("varchar", {

View file

@ -576,6 +576,16 @@ export default function () {
{ removeOnComplete: true, removeOnFail: true }, { removeOnComplete: true, removeOnFail: true },
); );
systemQueue.add(
"verifyLinks",
{},
{
repeat: { cron: "0 0 * * 0" },
removeOnComplete: true,
removeOnFail: true,
},
);
processSystemQueue(systemQueue); processSystemQueue(systemQueue);
} }

View file

@ -5,6 +5,7 @@ import { cleanCharts } from "./clean-charts.js";
import { checkExpiredMutings } from "./check-expired-mutings.js"; import { checkExpiredMutings } from "./check-expired-mutings.js";
import { clean } from "./clean.js"; import { clean } from "./clean.js";
import { setLocalEmojiSizes } from "./local-emoji-size.js"; import { setLocalEmojiSizes } from "./local-emoji-size.js";
import { verifyLinks } from "./verify-links.js";
const jobs = { const jobs = {
tickCharts, tickCharts,
@ -13,6 +14,7 @@ const jobs = {
checkExpiredMutings, checkExpiredMutings,
clean, clean,
setLocalEmojiSizes, setLocalEmojiSizes,
verifyLinks,
} as Record< } as Record<
string, string,
| Bull.ProcessCallbackFunction<Record<string, unknown>> | Bull.ProcessCallbackFunction<Record<string, unknown>>

View file

@ -0,0 +1,44 @@
import type Bull from "bull";
import { UserProfiles } from "@/models/index.js";
import { Not } from "typeorm";
import { queueLogger } from "../../logger.js";
import { verifyLink } from "@/services/fetch-rel-me.js";
import config from "@/config/index.js";
const logger = queueLogger.createSubLogger("verify-links");
export async function verifyLinks(
job: Bull.Job<Record<string, unknown>>,
done: any,
): Promise<void> {
logger.info("Verifying links...");
const usersToVerify = await UserProfiles.findBy({
fields: Not(null),
userHost: "",
});
for (const user of usersToVerify) {
for (const field of user.fields) {
if (!field || field.name === "" || field.value === "") {
continue;
}
if (field.value.startsWith("http") && user.user?.username) {
field.verified = await verifyLink(field.value, user.user.username);
}
}
if (user.fields.length > 0) {
try {
await UserProfiles.update(user.userId, {
fields: user.fields,
});
} catch (e) {
logger.error(`Failed to update user ${user.userId} ${e}`);
done(e);
}
}
}
logger.succ("All links successfully verified.");
done();
}

View file

@ -12,7 +12,9 @@ import type { UserProfile } from "@/models/entities/user-profile.js";
import { notificationTypes } from "@/types.js"; import { notificationTypes } from "@/types.js";
import { normalizeForSearch } from "@/misc/normalize-for-search.js"; import { normalizeForSearch } from "@/misc/normalize-for-search.js";
import { langmap } from "@/misc/langmap.js"; import { langmap } from "@/misc/langmap.js";
import { verifyLink } from "@/services/fetch-rel-me.js";
import { ApiError } from "../../error.js"; import { ApiError } from "../../error.js";
import config from "@/config/index.js";
import define from "../../define.js"; import define from "../../define.js";
export const meta = { export const meta = {
@ -58,6 +60,18 @@ export const meta = {
code: "INVALID_REGEXP", code: "INVALID_REGEXP",
id: "0d786918-10df-41cd-8f33-8dec7d9a89a5", id: "0d786918-10df-41cd-8f33-8dec7d9a89a5",
}, },
invalidFieldName: {
message: "Invalid field name.",
code: "INVALID_FIELD_NAME",
id: "8f81972e-8b53-4d30-b0d2-efb026dda673",
},
invalidFieldValue: {
message: "Invalid field value.",
code: "INVALID_FIELD_VALUE",
id: "aede7444-244b-11ee-be56-0242ac120002",
},
}, },
res: { res: {
@ -234,16 +248,29 @@ export default define(meta, paramDef, async (ps, _user, token) => {
} }
if (ps.fields) { if (ps.fields) {
for (const field of ps.fields) {
if (!field || field.name === "" || field.value === "") {
continue;
}
if (typeof field.name !== "string" || field.name === "") {
throw new ApiError(meta.errors.invalidFieldName);
}
if (typeof field.value !== "string" || field.value === "") {
throw new ApiError(meta.errors.invalidFieldValue);
}
if (field.value.startsWith("http")) {
field.verified = await verifyLink(field.value, user.username);
}
}
profileUpdates.fields = ps.fields profileUpdates.fields = ps.fields
.filter( .filter((x) => Object.keys(x).length !== 0)
(x) =>
typeof x.name === "string" &&
x.name !== "" &&
typeof x.value === "string" &&
x.value !== "",
)
.map((x) => { .map((x) => {
return { name: x.name, value: x.value }; return {
name: x.name,
value: x.value,
verified: x.verified,
};
}); });
} }

View file

@ -0,0 +1,33 @@
import { getHtml } from "@/misc/fetch.js";
import { JSDOM } from "jsdom";
import config from "@/config/index.js";
async function getRelMeLinks(url: string): Promise<string[]> {
try {
const html = await getHtml(url);
const dom = new JSDOM(html);
const relMeLinks = [
...dom.window.document.querySelectorAll("a[rel='me']"),
...dom.window.document.querySelectorAll("link[rel='me']"),
].map((a) => (a as HTMLAnchorElement | HTMLLinkElement).href);
return relMeLinks;
} catch {
return [];
}
}
export async function verifyLink(link: string, username: string): Promise<boolean> {
let verified = false;
if (link.startsWith("http")) {
const relMeLinks = await getRelMeLinks(link);
verified = relMeLinks.some((href) =>
new RegExp(
`^https?:\/\/${config.host.replace(
/[.*+\-?^${}()|[\]\\]/g,
"\\$&",
)}\/@${username.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&")}$`,
).test(href),
);
}
return verified;
}

View file

@ -38,7 +38,11 @@ export type UserDetailed = UserLite & {
createdAt: DateString; createdAt: DateString;
description: string | null; description: string | null;
ffVisibility: "public" | "followers" | "private"; ffVisibility: "public" | "followers" | "private";
fields: { name: string; value: string }[]; fields: {
name: string;
value: string;
verified?: boolean;
}[];
followersCount: number; followersCount: number;
followingCount: number; followingCount: number;
hasPendingFollowRequestFromYou: boolean; hasPendingFollowRequestFromYou: boolean;

View file

@ -436,10 +436,7 @@ onMounted(() => {
setPosition(); setPosition();
props.textarea.addEventListener("keydown", onKeydown); props.textarea.addEventListener("keydown", onKeydown);
document.body.addEventListener("mousedown", onMousedown);
for (const el of Array.from(document.querySelectorAll("body *"))) {
el.addEventListener("mousedown", onMousedown);
}
nextTick(() => { nextTick(() => {
exec(); exec();
@ -457,10 +454,7 @@ onMounted(() => {
onBeforeUnmount(() => { onBeforeUnmount(() => {
props.textarea.removeEventListener("keydown", onKeydown); props.textarea.removeEventListener("keydown", onKeydown);
document.body.removeEventListener("mousedown", onMousedown);
for (const el of Array.from(document.querySelectorAll("body *"))) {
el.removeEventListener("mousedown", onMousedown);
}
}); });
</script> </script>

View file

@ -57,15 +57,11 @@ onMounted(() => {
rootEl.style.top = `${top}px`; rootEl.style.top = `${top}px`;
rootEl.style.left = `${left}px`; rootEl.style.left = `${left}px`;
for (const el of Array.from(document.querySelectorAll("body *"))) { document.body.addEventListener("mousedown", onMousedown);
el.addEventListener("mousedown", onMousedown);
}
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
for (const el of Array.from(document.querySelectorAll("body *"))) { document.body.removeEventListener("mousedown", onMousedown);
el.removeEventListener("mousedown", onMousedown);
}
}); });
function onMousedown(evt: Event) { function onMousedown(evt: Event) {

View file

@ -126,7 +126,11 @@
</div> </div>
</FormFolder> </FormFolder>
<template #caption>{{ <template #caption>{{
i18n.ts._profile.metadataDescription i18n.t("_profile.metadataDescription", {
a: '<code><a></code>',
l: '<code><a></code>',
rel: `rel="me" href="https://${host}/@${$i.username}"`
})
}}</template> }}</template>
</FormSlot> </FormSlot>
@ -173,6 +177,7 @@ import { i18n } from "@/i18n";
import { $i } from "@/account"; import { $i } from "@/account";
import { langmap } from "@/scripts/langmap"; import { langmap } from "@/scripts/langmap";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
import { host } from "@/config";
const profile = reactive({ const profile = reactive({
name: $i?.name, name: $i?.name,

View file

@ -288,10 +288,17 @@
<div v-if="user.fields.length > 0" class="fields"> <div v-if="user.fields.length > 0" class="fields">
<dl <dl
v-for="(field, i) in user.fields" v-for="(field, i) in user.fields"
:class="field.verified ? 'verified' : ''"
:key="i" :key="i"
class="field" class="field"
> >
<dt class="name"> <dt class="name">
<i
v-if="field.verified"
class="ph-bold ph-seal-check ph-lg ph-fw"
style="padding: 5px"
v-tooltip="i18n.ts.verifiedLink"
></i>
<Mfm <Mfm
:text="field.name" :text="field.name"
:plain="true" :plain="true"
@ -748,6 +755,12 @@ onUnmounted(() => {
margin-bottom: 8px; margin-bottom: 8px;
} }
&.verified {
background-color: var(--hover);
border-radius: 10px;
color: var(--badge) !important;
}
> .name { > .name {
width: 30%; width: 30%;
overflow: hidden; overflow: hidden;

View file

@ -384,6 +384,27 @@ async function deleteProfile() {
} }
</script> </script>
<style>
html,
body {
width: 100%;
height: 100%;
overflow: clip;
position: fixed;
top: 0;
left: 0;
}
#calckey_app {
width: 100%;
height: 100%;
overflow: clip;
position: absolute;
top: 0;
left: 0;
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
.menu-enter-active, .menu-enter-active,
.menu-leave-active { .menu-leave-active {

View file

@ -410,6 +410,27 @@ const wallpaper = localStorage.getItem("wallpaper") != null;
console.log(mainRouter.currentRoute.value.name); console.log(mainRouter.currentRoute.value.name);
</script> </script>
<style>
html,
body {
width: 100%;
height: 100%;
overflow: clip;
position: fixed;
top: 0;
left: 0;
}
#calckey_app {
width: 100%;
height: 100%;
overflow: clip;
position: absolute;
top: 0;
left: 0;
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
.widgetsDrawer-enter-active, .widgetsDrawer-enter-active,
.widgetsDrawer-leave-active { .widgetsDrawer-leave-active {

View file

@ -2,5 +2,6 @@ namespace MisskeyEntity {
export type Field = { export type Field = {
name: string name: string
value: string value: string
verified?: string
} }
} }