diff --git a/CHANGELOG.md b/CHANGELOG.md index f24c80fc94..281416fd76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,30 @@ --> +## 12.98.0 (2021/12/03) + +### Improvements +- API: /antennas/notes API で日付による絞り込みができるように +- クライアント: アンケートに投票する際に確認ダイアログを出すように +- クライアント: Renoteなノート詳細ページから元のノートページに遷移できるように +- クライアント: 画像ポップアップでクリックで閉じられるように +- クライアント: デザインの調整 +- フォロワーを解除できる機能 + +### Bugfixes +- クライアント: LTLやGTLが無効になっている場合でもUI上にタブが表示される問題を修正 +- クライアント: ログインにおいてパスワードが誤っている際のエラーメッセージが正しく表示されない問題を修正 +- クライアント: リアクションツールチップ、Renoteツールチップのユーザーの並び順を修正 +- クライアント: サウンドのマスターボリュームが正しく保存されない問題を修正 +- クライアント: 一部環境において通知が表示されると操作不能になる問題を修正 +- クライアント: モバイルでタップしたときにツールチップが表示される問題を修正 +- クライアント: リモートインスタンスのノートに返信するとき、対象のノートにそのリモートインスタンス内のユーザーへのメンションが含まれていると、返信テキスト内にローカルユーザーへのメンションとして引き継がれてしまう場合がある問題を修正 +- クライアント: 画像ビューワーで全体表示した時に上側の一部しか表示されない画像がある問題を修正 +- API: ユーザーを取得時に条件によっては内部エラーになる問題を修正 + +### Changes +- クライアント: ノートにモデレーターバッジを表示するのを廃止 + ## 12.97.0 (2021/11/19) ### Improvements diff --git a/README.md b/README.md index a60f71cacf..799be299d5 100644 --- a/README.md +++ b/README.md @@ -1,116 +1,57 @@ -[![Misskey](/assets/about/banner.svg)](https://join.misskey.page/) - -

Misskey

+[![Misskey](https://github.com/misskey-dev/assets/blob/main/banner.png?raw=true)](https://join.misskey.page/)
-[![Dependencies](https://img.shields.io/david/misskey-dev/misskey.svg?style=for-the-badge&logo=npm)](https://david-dm.org/misskey-dev/misskey) -[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge&logo=github)](http://makeapullrequest.com) -[![Awesome Humane Tech](https://raw.githubusercontent.com/humanetech-community/awesome-humane-tech/main/humane-tech-badge.svg?sanitize=true)](https://github.com/humanetech-community/awesome-humane-tech) +**🌎 A forever evolving, interplanetary microblogging platform. 🚀** -**A forever evolving, interplanetary microblogging platform.** +**Misskey** is a distributed microblogging platform with advanced features such as Reactions and a highly customizable UI. -Misskey is a decentralized microblogging platform born on Earth. -Since it exists within the Fediverse (a universe where various social media platforms are organized), -it is mutually linked with other social media platforms. -Why don't you take a short break from the hustle and bustle of the city, and dive into a new Internet? Find an instance! +[Learn more](https://misskey-hub.net/) + +--- + +[✨ Find an instance](https://misskey-hub.net/instances.html) +• +[📦 Create your own instance](https://misskey-hub.net/docs/install.html) +• +[🛠️ Contribute](./CONTRIBUTING.md) +• +[🚀 Join the community](https://discord.gg/Wp8gVStHW3) + +--- Become a Patron!
---- +
-Do you have a question? Or are you experiencing trouble? -Visit [our forum](https://forum.misskey.io/)! + ---- +## ✨ Features +- **ActivityPub support**\ + It is possible to interact with other software. +- **Reactions**\ + You can add "reactions" to each post, making it easy for you to express your feelings. +- **Drive**\ + An interface to manage uploaded files such as images, videos, sounds, etc. + You can also organize your favorite content into folders, making it easy to share again. +- **Rich Web UI**\ + Misskey has a rich WebUI by default. + It is highly customizable by flexibly changing the layout and installing various widgets and themes. + Furthermore, plug-ins can be created using AiScript, a original programming language. +- and more... -![](https://ja.mstdn.wiki/images/e/ed/Deck.jpg) +
-:sparkles: Features ----------------------------------------------------------------- - +
-

Posting

-

-Post your ideas, discussion topics, fun moments, or anything else you want to share! Misskey supports text, emoji, pictures, videos, and polls! -

- ---- - -

Reactions

-

-Reactions are the simplest way to respond to others' posts. Simply pick a reaction emote from the list! Reactions on Misskey are much more expressive than other social media services which only allow “liking”. -

- ---- - -

Interface

-

-Customize the UI to your own tastes! No UI will work for everyone, so Misskey is completely customizable. Make Misskey *yours* by editing the style, adjusting timeline layouts, and placing widgets. -

- ---- - -

Misskey Drive

-

-Organize and store your files! Want to post a picture you have already uploaded? Wish you could organize your files into folders? Misskey Drive is a solution! -

- ---- - -...and more! - -:package: Create your own instance ----------------------------------------------------------------- -Please see the [Setup and Installation Guide](https://misskey-hub.net/docs/install/install.html). - -:wrench: Contribution ----------------------------------------------------------------- -Please see the [Contribution Guide](./CONTRIBUTING.md). - -### Collaborators - - - - - - - - - - - - - - - - - - - - - -
syuiloAyaMorisawamei23acid-chickenrinsukitamainaXelticau1-liquid
@syuilo@AyaMorisawa@mei23@acid-chicken@rinsuki@tamaina@Xeltica@u1-liquid
- ---- - -To receive updates of this repo, follow [@repo@misskey.io](https://misskey.io/@repo) on fediverse. - -Related projects ----------------------------------------------------------------- -- [misskey.js](https://github.com/misskey-dev/misskey.js) - Misskey SDK for JavaScript -- [mfm.js](https://github.com/misskey-dev/mfm.js) - MFM parser - -Sponsors ----------------------------------------------------------------- +## Sponsors
RSS3
-:heart: Backers ----------------------------------------------------------------- +## Backers diff --git a/assets/about/banner.svg b/assets/about/banner.svg deleted file mode 100644 index 75308c0950..0000000000 --- a/assets/about/banner.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index cd69d921b8..c831fafff1 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -734,7 +734,10 @@ translate: "ترجم" translatedFrom: "تُرجم من {x}" accountDeletionInProgress: "حذف الحساب جارٍ" usernameInfo: "الاسم الذي يميزك عن بافي مستخدمي هذا الخادم، يمكنك استخدام الحروف اللاتينية (a~z, A~Z) والأرقام (0~9) والشرطة السفلية (_). لا يمكنك تغييره بعد تسجيله." +keepCw: "أبقِ على تحذيرات المحتوى" lastCommunication: "آخر تواصل" +resolved: "عولج" +unresolved: "لم يعالج" itsOn: "مفعّل" itsOff: "معطّل" emailRequiredForSignup: "عنوان البريد الإلكتروني إلزامي للتسجيل" @@ -747,6 +750,16 @@ makeReactionsPublicDescription: "هذا سيجعل قائمة تفاعلاتك classic: "تقليدي" muteThread: "اكتم النقاش" unmuteThread: "ارفع الكتم عن النقاش" +deleteAccountConfirm: "سيحذف حسابك نهائيًا، أتريد المتابعة؟" +incorrectPassword: "كلمة السر خاطئة." +_emailUnavailable: + used: "هذا البريد الإلكتروني مستخدم" + format: "صيغة البريد الإلكتروني غير صالحة" + mx: "خادم البريد الإلكتروني غير صالح" + smtp: "خادم البريد الإلكتروتي لا يستجيب" +_ffVisibility: + public: "علني" + private: "خاص" _signup: almostThere: "كدت تنتهي" emailAddressInfo: "رجاءً أدخل بريدك الإلكتروني." @@ -829,6 +842,7 @@ _mfm: font: "الخط" rainbow: "قوس قزح" rainbowDescription: "اجعل المحتوى يظهر بألوان الطيف" + rotate: "تدوير" _reversi: gameSettings: "إعدادات اللعبة" chooseBoard: "اختر اللوح" @@ -980,9 +994,13 @@ _tutorial: step7_2: "إذا أردت معرفة المزيد عن ميسكي زر {help}." step7_3: "حظًا سعيدًا واستمتع بوقتك مع ميسكي! 🚀" _2fa: + alreadyRegistered: "سجلت سلفًا جهازًا للاستيثاق بعاملين." registerDevice: "سجّل جهازًا جديدًا" registerKey: "تسجيل مفتاح أمان جديد" step1: "أولًا ثبّت تطبيق استيثاق على جهازك (مثل {a} و{b})." + step2: "امسح رمز الاستجابة السريعة الموجد على الشاشة." + step3: "أدخل الرمز الموجود في تطبيقك لإكمال التثبيت." + step4: "من هذه اللحظة أثناء ولوجك سيُطلب منك الرمز." _permissions: "read:account": "اعرض معلومات حسابك" "write:account": "تعديل معلومات حسابك" @@ -993,6 +1011,7 @@ _permissions: "read:favorites": "اعرض المفضلة" "write:favorites": "عدّل المفضلة" "read:following": "اعرض معلومات متابَعيك" + "write:following": "تابع أو ألغ متابعة حسابات" "read:messaging": "اعرض المحادثات" "write:messaging": "اكتب أو احذف رسائل محادثة" "read:mutes": "اعرض قائمة المستخدمين المكتومين" @@ -1005,11 +1024,14 @@ _permissions: "write:votes": "صوّت" "read:pages": "اعرض صفحاتك" "write:pages": "عدّل أو احذف صفحاتك" + "read:page-likes": "يعرض ما أعجبك من ملاحظات في صفحات" "read:user-groups": "اعرض فِرق المستخدمين" "write:user-groups": "عدّل أو احذف فِرق المستخدمين" + "read:channels": "طالع قنواتك" "write:channels": "عدّل القنوات" "read:gallery": "اعرض المعرض" "write:gallery": "عدّل المعرض" + "read:gallery-likes": "يعرض ما أعجبك من مشاركات المعرض" _auth: shareAccess: "أتريد التفويض لـ \"{name}\" بالوصول لحسابك؟" shareAccessAsk: "هل تخول لهذا التطبيق الوصول لحسابك؟" @@ -1173,6 +1195,7 @@ _rooms: tv: "تلفاز" pinguin: "بطريق" sofa: "أريكة" + bin: "سلة مهملات" banknote: "أوراق نقدية" _pages: newPage: "أنشئ صفحة جديدة" @@ -1212,6 +1235,7 @@ _pages: name: "اسم المتغير" text: "العنوان" default: "القيمة الافتراضية" + textareaInput: "مدخل نصي متعدد الأسطر" _textareaInput: name: "اسم المتغير" text: "العنوان" @@ -1227,6 +1251,7 @@ _pages: note: "ملاحظة مضمّنة" _note: id: "معرّف الملاحظة" + idDescription: "كبديل يمكنك إدخال رابك الملاحظة هنا" detailed: "عرض مفصّل" switch: "بدّل" _switch: diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 39748e2b23..69d90c7624 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -792,6 +792,7 @@ pubSub: "Pub/Sub Benutzerkonten" lastCommunication: "Letzte Kommunikation" resolved: "Gelöst" unresolved: "Ungelöst" +breakFollow: "Follower entfernen" itsOn: "Eingeschaltet" itsOff: "Ausgeschaltet" emailRequiredForSignup: "Angaben einer Email-Adresse als benötigt markieren" @@ -808,6 +809,8 @@ ffVisibility: "Sichtbarkeit von Gefolgten/Followern" ffVisibilityDescription: "Konfiguriere wer sehen kann, wem du folgst sowie wer dir folgt." continueThread: "Weiteren Threadverlauf anzeigen" deleteAccountConfirm: "Dein Benutzerkonto wird unwiderruflich gelöscht. Trotzdem fortfahren?" +incorrectPassword: "Falsches Passwort." +voteConfirm: "Wirklich für \"{choice}\" abstimmen?" _emailUnavailable: used: "Diese Email-Adresse wird bereits verwendet" format: "Das Format dieser Email-Adresse ist ungültig" @@ -931,6 +934,8 @@ _mfm: rainbowDescription: "Lässt den Inhalt in Regenbogenfarben erscheinen." sparkle: "Glitzer" sparkleDescription: "Verleiht Inhalt einen glitzernden Partikeleffekt." + rotate: "Drehen" + rotateDescription: "Dreht den Inhalt um einen angegebenen Winkel" _reversi: reversi: "Reversi" gameSettings: "Spieleinstellungen" diff --git a/locales/en-US.yml b/locales/en-US.yml index 37da6fdc95..5388a7a636 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -808,6 +808,8 @@ ffVisibility: "Follows/Followers Visibility" ffVisibilityDescription: "Allows you to configure who can see who you follow and who follows you." continueThread: "View thread continuation" deleteAccountConfirm: "This will irreversibly delete your account. Proceed?" +incorrectPassword: "Incorrect password." +voteConfirm: "Confirm your vote for \"{choice}\"?" _emailUnavailable: used: "This email address is already being used" format: "The format of this email address is invalid" @@ -931,6 +933,8 @@ _mfm: rainbowDescription: "Makes the content appear in rainbow colors." sparkle: "Sparkle" sparkleDescription: "Gives content a sparkling particle effect." + rotate: "Rotate" + rotateDescription: "Turns content by a specified angle." _reversi: reversi: "Reversi" gameSettings: "Game settings" diff --git a/locales/eo-UY.yml b/locales/eo-UY.yml index 7b641303b1..a57206e090 100644 --- a/locales/eo-UY.yml +++ b/locales/eo-UY.yml @@ -2,18 +2,18 @@ _lang_: "Esperanto" headlineMisskey: "Jen la reto konektata de notoj" introMisskey: "Bonvenon! Misskey estas malfermitkoda malcentraliza etbloga servo.\nKreu \"noto\"n por paroli vian penson al iuj ĉirkaŭ vi. 📡\nLa funkcion \"reago\" ebligas esprimi rapide vian senton pri ies noto en Fediverso. 👍\nBonvole esploru novan mondon. 🚀" -monthAndDay: "La {day}a de la {month}a" +monthAndDay: "la {day}a de la {month}a" search: "Serĉi" notifications: "Sciigoj" username: "Uzantnomo" password: "Pasvorto" forgotPassword: "Ĉu vi forgesis pasvorton?" -fetchingAsApObject: "Informpetado de kunfederaĵo…" -ok: "Akcepteble" -gotIt: "Mi komprenas" +fetchingAsApObject: "Informpetado de la Fediverso…" +ok: "OK" +gotIt: "Kompreni" cancel: "Nuligi" enterUsername: "Entajpu uzantnomon" -renotedBy: "Noto plusendita de {user}" +renotedBy: "Plusendita de {user}" noNotes: "Neniu noto!" noNotifications: "Vi ne havas sciigojn." instance: "Nodo" @@ -35,22 +35,22 @@ addUser: "Aldoni uzanton" favorite: "Preferi" favorites: "Preferaĵoj" unfavorite: "Malpreferi" -favorited: "Aldonita al via listo de preferaĵoj." -alreadyFavorited: "Jam aldonita al via listo de preferaĵoj." -cantFavorite: "Ĝi ne povis esti aldonita al via listo de preferaĵoj." +favorited: "Aldonita al viaj preferaĵoj." +alreadyFavorited: "Jam aldonita al viaj preferaĵoj." +cantFavorite: "Oni ne povis aldoni al viaj preferaĵoj." pin: "Alpingli" unpin: "Depingli" copyContent: "Kopii enhavon" copyLink: "Kopii ligilon" delete: "Forviŝi" deleteAndEdit: "Forviŝi kaj redakti" -deleteAndEditConfirm: "Ĉu vi certas ke vi volas redakti forviŝinte la noton? Tio forviŝos ankaŭ ĉiujn reagojn, plusendojn, kaj respondojn apartenantajn al ĝi." +deleteAndEditConfirm: "Ĉu vi certas ke vi volas redakti foriginte la noton? Tio forviŝos reagojn, plusendojn, kaj respondojn ĉiujn apartenantajn al ĝi." addToList: "Aldoni al listo" sendMessage: "Sendi mesaĝon" copyUsername: "Kopii uzantnomon" searchUser: "Serĉi uzanton" reply: "Respondi" -loadMore: "Vidu pli" +loadMore: "Vidi pli" showMore: "Vidi pli" youGotNewFollower: "eksekvis vin" receiveFollowRequest: "Peto de sekvado estas ricevita" @@ -77,10 +77,11 @@ manageLists: "Administri liston" error: "Eraro" somethingHappened: "Problemo okazis" retry: "Provi denove" +serverIsDead: "La servilo ne respondas. Vole atendu iom kaj penu denove." enterListName: "Entajpu nomon de la listo" privacy: "Privateco" makeFollowManuallyApprove: "Eksekvi vin devas peti al vi" -defaultNoteVisibility: "Implicitaĵo de videbleco" +defaultNoteVisibility: "Implicita videbleco de la noto" follow: "Sekvi" followRequest: "Peti de sekvado" followRequests: "Petoj de sekvado" @@ -88,10 +89,10 @@ unfollow: "Ne plu sekvi" followRequestPending: "Atendado akcepti vian peton de eksekvado" enterEmoji: "Entajpu emoĵion" renote: "Plusendi la noton" -unrenote: "Malfari plusendadon" +unrenote: "Malfari plusendon" renoted: "Sukcese plusendita" cantRenote: "Oni ne povas plusendi la noton." -cantReRenote: "Plusendo de noto ne estas plusendebla." +cantReRenote: "Plusendo ne estas plusendebla." quote: "Citi" pinnedNote: "Alpinglita noto" pinned: "Alpingli" @@ -101,7 +102,7 @@ sensitive: "Enhavo ne estas deca por laborejo (NSFW)" add: "Aldoni" reaction: "Reagoj" reactionSettingDescription: "Agordi la reagojn kiujn vi volas prefere montrigi ĉe la elektilo de reagoj" -rememberNoteVisibility: "Rememori la agordon de videbleco de la noto laste sendita " +rememberNoteVisibility: "Rememori la agordon de videbleco de la laste sendita" attachCancel: "Deigi aldonaĵon" markAsSensitive: "Troviĝi NSFW" unmarkAsSensitive: "Ne troviĝi NSFW" @@ -121,16 +122,16 @@ selectAntenna: "Elekti antenon" selectWidget: "Elekti enestraĵon" editWidgets: "Redakti fenestraĵon" editWidgetsExit: "Fini la redaktadon" -customEmojis: "Personecigitaj emoĵioj" emoji: "Emoĵio" emojis: "Emoĵio" -emojiName: "Nomo de emoĵio" +emojiName: "Nomo de la emoĵio" emojiUrl: "URL de la emoĵio" addEmoji: "Aldoni emoĵion" settingGuide: "Agordaj rekomendoj" -cacheRemoteFiles: "Stapli transajn dosierojn" -flagAsBot: "Agordo por robota uzanto" -flagAsCat: "Agi kat-iĝon" +cacheRemoteFiles: "Stapli forajn dosierojn" +flagAsBot: "Fari la flagon por robota uzanto" +flagAsCat: "Fari la flagon por kat-iĝi" +autoAcceptFollowed: "Aŭtomate akcepti la peton de sekvado far uzantoj kiujn vi sekvas" addAccount: "Aldoni konton" showOnRemote: "Vidi ĉe la surloka nodo" general: "Ĝenerala" @@ -140,7 +141,7 @@ removeWallpaper: "Forviŝi ekranfonon. " searchWith: "Serĉi: {q}" youHaveNoLists: "Vi ne havas listojn." followConfirm: "Ĉu vi certas ke vi volas sekvi {name}'(o)n?" -host: "Gastigo" +host: "Nodo" selectUser: "Elekti uzanton" recipient: "Ricevonto" annotation: "Komentarioj" @@ -164,8 +165,9 @@ disk: "Disko" instanceInfo: "Informoj pri la nodo" statistics: "Statistikoj" clearCachedFiles: "Malplenigi la staplon" -clearCachedFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn transajn dosierojn en la staplo?" +clearCachedFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn forajn dosierojn en la staplo?" blockedInstances: "Blokitaj nodoj" +muteAndBlock: "Silentigi / Bloki" mutedUsers: "Silentigitaj uzantoj" blockedUsers: "Blokitaj uzantoj" noUsers: "Neniu uzanto" @@ -175,7 +177,7 @@ pinLimitExceeded: "Vi ne povas alpingli pli" done: "Fini" processing: "Prilaborado…" preview: "Antaŭmontro" -default: "Defaŭlta" +default: "Implicitaĵo" noCustomEmojis: "Neniu emoĵio" noJobs: "Neniu laboro" federating: "Federantaj" @@ -195,7 +197,7 @@ currentPassword: "Aktuala pasvorto" newPassword: "Nova pasvorto" newPasswordRetype: "Reentajpu la novan pasvorton" attachFile: "Aldoni dosieron" -more: "Plu!" +more: "Pli!" featured: "Maksimumi" usernameOrUserId: "Uzantnomo aŭ identigilo de uzanto" noSuchUser: "Neniuj uzantoj trovitaj" @@ -204,8 +206,8 @@ announcements: "Novaĵoj" imageUrl: "URL de la bildo" remove: "Forigi" removed: "Forigita" -removeAreYouSure: "Ĉu vi certas ke vi volas forigi \"{x}\"'(o)n?" -deleteAreYouSure: "Ĉu vi certas ke vi volas forviŝi \"{x}\"'(o)n?" +removeAreYouSure: "Ĉu vi certas ke vi volas forigi \"{x}\"n?" +deleteAreYouSure: "Ĉu vi certas ke vi volas forviŝi \"{x}\"'?" resetAreYouSure: "Ĉu vi certas restarigi?" saved: "Konservita" messaging: "Retbabili" @@ -225,13 +227,13 @@ agreeTo: "Mi akceptas {0}'(o)n" tos: "Kondiĉoj de uzado" start: "Komenciĝi" home: "Hejma" -remoteUserCaution: "Ĉi tiuj infomoj estas ne tute ekzaktaj pro transa uzanto." +remoteUserCaution: "Ĉi tiuj infomoj de la uzanto el fora nodo, ne estas tute ekzaktaj." activity: "Aktiveco" images: "Bildoj" birthday: "Naskiĝdato" yearsOld: "{age} jaroj aĝa" registeredDate: "Dato de registriĝo" -location: "Loko" +location: "Kie" theme: "Koloraro" themeForLightMode: "Luma kolararo en la luma modo" themeForDarkMode: "Malluma kolararo en la malluma modo" @@ -253,7 +255,7 @@ deleteFolder: "Forviŝi dosierujon" addFile: "Aldoni dosieron" emptyDrive: "La disko malplenas" emptyFolder: "La dosierujo malplenas" -unableToDelete: "Ne forigebla" +unableToDelete: "Ne forviŝebla" inputNewFileName: "Entajpu novan nomon de la dosiero" inputNewDescription: "Entajpu novan priskribon" inputNewFolderName: "Entajpu novan nomon de la dosierujo" @@ -266,9 +268,11 @@ nsfw: "Enhavo ne estas deca por laborejo (NSFW)" disconnectedFromServer: "Malkonektita de servilo" reload: "Reŝargi" doNothing: "Ignori" +reloadConfirm: "Ĉu vi volas reŝargi?" watch: "Observi" unwatch: "Malobservi" accept: "Permesi" +reject: "Malakcepti" normal: "Normala" instanceName: "Nomo de la nodo" instanceDescription: "Priskribo de la nodo " @@ -291,20 +295,22 @@ registration: "Registri" enableRegistration: "Ebligi novan uzanton registriĝon" invite: "Inviti" driveCapacityPerLocalAccount: "Volumo de disko po unu loka uzanto" -driveCapacityPerRemoteAccount: "Volumo de disko po unu transa uzanto" +driveCapacityPerRemoteAccount: "Volumo de disko po unu fora uzanto" iconUrl: "URL de la ikono (retpaĝsimbolo, ktp)" bannerUrl: "URL de standardo" backgroundImageUrl: "URL de fona bildo" basicInfo: "Baza informo" pinnedUsers: "Alpinglita uzanto" +pinnedUsersDescription: "Listigu uzantnomojn apartige en ĉiu linio por alpingli al la paĝoj ekz \"Esplori\"." pinnedPages: "Alpinglitaj paĝoj" +pinnedPagesDescription: "Listigu dosierindiko apartige en ĉiu linio por alpingli al la ĉefpaĝo de la nodo." pinnedNotes: "Alpinglita noto" hcaptcha: "hCaptcha" enableHcaptcha: "Ebligi hCaptcha" hcaptchaSiteKey: "Reteja ŝlosilo" hcaptchaSecretKey: "Sekreta ŝlosilo" recaptcha: "reCAPTCHA" -enableRecaptcha: "Ebligi reCAPTCHA'on" +enableRecaptcha: "Ebligi reCAPTCHA" recaptchaSiteKey: "Reteja ŝlosilo" recaptchaSecretKey: "Sekreta ŝlosilo" antennas: "Antenoj" @@ -338,15 +344,17 @@ moderator: "Kontrolisto" nUsersMentioned: "{n} uzanto(j) menciis" securityKey: "Sekureca ŝlosilo" securityKeyName: "Nomo de la ŝlosilo" +registerSecurityKey: "Registri ŝlosilon de sekureco" lastUsed: "Plej malnove uzita" unregister: "Malregistriĝi" passwordLessLogin: "Ensaluti sen pasvorto" resetPassword: "Restarigi pasvorton" newPasswordIs: "La nova pasvorto estas {password}." -share: "Diskonigi" +reduceUiAnimation: "Redukti la animacioj de la fasado" +share: "Kundividi" notFound: "Ne trovita" cacheClear: "Malplenigi staplon" -markAsReadAllNotifications: "Marki ĉiujn sciigojn kiel legito" +markAsReadAllNotifications: "Marki ĉiujn sciigojn kiel legita" help: "Manlibro de uzado" inputMessageHere: "Entajpu masaĝo tie ĉi" close: "Fermi" @@ -354,10 +362,11 @@ group: "Grupo" groups: "Grupoj" createGroup: "Krei grupon" ownedGroups: "Administrataj grupoj" -joinedGroups: "La grupoj kiujn la uzanto aliĝis" +joinedGroups: "Al grupoj kiuj vi aliĝis" invites: "Inviti" groupName: "Grupa nomo" members: "Membroj" +transfer: "Movi" messagingWithUser: "Babili private" messagingWithGroup: "Babili grupe" title: "Titolo" @@ -366,6 +375,7 @@ enable: "Ebligi" next: "Sekve" retype: "Retajpu" noteOf: "Noto de {user}" +inviteToGroup: "Inviti al grupo" quoteAttached: "Kun citaĵo" quoteQuestion: "Ĉu vi aldonas citaĵon?" noMessagesYet: "Ankoraŭ neniu mesaĝo" @@ -374,27 +384,38 @@ onlyOneFileCanBeAttached: "Oni povas aldoni nur unu dosieron po mesaĝo." signinRequired: "Bonvolu ensaluti" invitations: "Inviti" invitationCode: "Invita kodo" +available: "Disposabla" unavailable: "Ne disponebla" +usernameInvalidFormat: "La uzantnomo povas enhavi minusklajn kaj majusklajn literojn, numerojn, nur kaj '_'." +tooShort: "Tro mallonga" +tooLong: "Tro longa" +weakPassword: "Malforta pasvorto" +normalPassword: "Normala pasvorto" +strongPassword: "Forta pasvorto" passwordMatched: "Konforma" passwordNotMatched: "Nekonforma" +signinWith: "Ensaluti kun {x}" or: "Aŭ" language: "Lingvo" uiLanguage: "Lingvo de fasado" aboutX: "Pri {x}" -useOsNativeEmojis: "Oni uzas la emoĵioj de la denaska sistemo" +useOsNativeEmojis: "Uzi la emoĵiojn implicitan de la operaciumo" youHaveNoGroups: "Neniuj grupoj" +noHistory: "Neniom historio" +signinHistory: "Historio de aliroj al la konto" doing: "Traktado..." category: "Kategorio" tags: "Etikedoj" +docSource: "Fonto de la dokumento" createAccount: "Krei konton" existingAccount: "Ekzista konto" regenerate: "Regeneri" fontSize: "Tipara grando" noFollowRequests: "Vi ne havas peto de sekvado" -openImageInNewTab: "Fermi la bildon en nova tablo" +openImageInNewTab: "Malfermi la bildojn en nova tablo" dashboard: "Stirpanelo" local: "Loka" -remote: "Transa" +remote: "Fora" total: "Entute" appearance: "Eksteraĵo" clientSettings: "Agordoj de kliento" @@ -402,6 +423,7 @@ accountSettings: "Agordoj de konto" numberOfDays: "Nombro de tagoj" hideThisNote: "Kaŝi la noton" objectStorageBaseUrl: "Baza URL" +objectStoragePrefix: "Prefix" objectStorageRegion: "Regiono" objectStorageUseSSL: "Oni uzas SSL" serverLogs: "Servila protokolo" @@ -416,7 +438,7 @@ volume: "Laŭteco" masterVolume: "Baza laŭteco" details: "Detaloj" chooseEmoji: "Elekti emoĵion" -recentUsed: "Lastatempaj uzitaj" +recentUsed: "Lastatempe uzitaj" install: "Instali" uninstall: "Malinstali" installedApps: "Instalita programo" @@ -425,10 +447,12 @@ installedDate: "Dato de instalado" lastUsedDate: "Lastfoje uzita je" state: "Stato" sort: "Ordigado" +ascendingOrder: "Kreski" +descendingOrder: "Malkreski" scratchpad: "Malneta redaktilo" output: "Elmeto" script: "Skripto" -disablePagesScript: "Malebligi AiScripto en la paĝoj" +disablePagesScript: "Malebligi AiScript en la paĝoj" deleteAllFiles: "Forviŝi ĉiujn dosierojn" deleteAllFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn dosierojn?" removeAllFollowing: "Ĉesi sekvi ĉiujn sekvatojn" @@ -438,7 +462,8 @@ menu: "Menuo" addItem: "Aldoni novaĵon" rooms: "Ĉambro" deletedNote: "Forviŝita noto" -invisibleNote: "Malpublika noto" +invisibleNote: "Malpublikigita noto" +enableInfiniteScroll: "Ebligi infinitan rulumon" visibility: "Videbleco" poll: "Balotujo" useCw: "Kaŝi enhavo" @@ -453,16 +478,23 @@ author: "Aŭtoro" manage: "Administro" plugins: "Kromaĵoj" deck: "Kartaro" +useFullReactionPicker: "Uzi la tuton de la elektilon de reagoj" width: "Larĝeco" height: "Alteco" +large: "Granda" medium: "Meza" small: "Malgranda" +generateAccessToken: "Generi ĵetonon de aliro" +permission: "Permesoj" +enableAll: "Ebligi ĉiujn" +disableAll: "Malebligi ĉiujn" +notificationType: "Tipo de sciigoj" edit: "Redakti" emailServer: "Retpoŝta servilo" email: "Retpoŝto" emailAddress: "Retpoŝta adreso" smtpConfig: "Agordoj de SMTP servilo" -smtpHost: "Gastigo" +smtpHost: "Transa servilo" smtpPort: "Pordo" smtpUser: "Uzantnomo" smtpPass: "Pasvorto" @@ -471,13 +503,20 @@ userSaysSomething: "{name} parolis ion" makeActive: "Aktivigi" display: "Vidi" copy: "Kopii" +metrics: "mezurciferoj" overview: "Resumo" +logs: "Protokoloj" +delayed: "Prokrasto " database: "Datumbazo" channel: "Kanalo" create: "Krei" notificationSetting: "Agordoj de sciigoj" useGlobalSetting: "Oni uzas malloka agordo" +other: "Aliaj" +regenerateLoginToken: "Regeneri la ĵetonon de aliro" fileIdOrUrl: "Dosiera identigilo aŭ URL" +chatOpenBehavior: "Konduto por malfermi la fenestron de babilejo" +behavior: "Konduto" sample: "Ekzemplo" abuseReports: "Signaloj" reportAbuse: "Signalo" @@ -485,20 +524,21 @@ reportAbuseOf: "Signali kontraŭ {name}'(o)" send: "Sendi" openInNewTab: "Malfermi en nova langeto" editTheseSettingsMayBreakAccount: "Redakti ĉi tiujn agordojn povas damaĝi vian konton." -instanceTicker: "Informoj pri la nodo kiu dissendas la noton" +instanceTicker: "Nomo de la nodo sendinta notojn" +waitingFor: "Atendado pro {x}" random: "Hazarde" system: "Sistemo" desktop: "Labortablo" createNew: "Krei novan" optional: "Opciaj" public: "Publika" -i18nInfo: "Misskey estas tradukata en diversaj lingvoj far volontuloj. Oni povas kontribui por la tradukado ĉe {link}." +i18nInfo: "Misskey estas tradukata en diversaj lingvoj de volontuloj. Oni povas kontribui ĉe {link}." accountInfo: "Kontaj Informoj" notesCount: "La nombro de notoj" repliesCount: "La nombro de respondoj senditaj" -renotesCount: "La nombro de notoj kiujn la uzanto plusendis" +renotesCount: "La nombro de notoj plusenditaj de la uzanto" repliedCount: "La nombro de respondoj ricevitaj" -renotedCount: "La nombro de uzantulaj notoj plusenditaj" +renotedCount: "La nombro de plusendoj de la notoj skribitaj de la uzanto" followingCount: "La nombro de sekvatoj" followersCount: "La nombro de sekvantoj" sentReactionsCount: "La nombro de la reagoj senditaj" @@ -512,10 +552,15 @@ noteFavoritesCount: "La nombro de notoj preferataj" pageLikesCount: "La nombro de paĝoj kiun la uzanto preferas" pageLikedCount: "La nombro de uzantoj, kiuj preferas paĝon de ĉi tiu uzanto" contact: "Kontakto" +useSystemFont: "Uzi la tiparon implicitan de la sistemo" +developer: "Evoluiganto" makeExplorable: "Videbligi konton sur la paĝo \"Esplori\"" +makeExplorableDescription: "Se vi elŝaltas tiun, via konto ne montros en la paĝo \"Esplori\"." duplicate: "Duobligi" left: "Maldekstra" center: "Centra" +wide: "Vasta" +narrow: "Malvasta" showTitlebar: "Videbligi titolan stangon" clearCache: "Malplenigi staplon" onlineUsersCount: "{n} uzanto(j) estas surlinea" @@ -525,9 +570,11 @@ myTheme: "Miaj koloraroj" backgroundColor: "Fona koloro" textColor: "Teksto" saveAs: "Konservi kiel…" +advanced: "Altnivela" value: "Valoro" createdAt: "Kreita je" updatedAt: "Laste ĝisdatigita" +saveConfirm: "Ĉu vi konservas la ŝanĝon?" deleteConfirm: "Ĉu certas forviŝi?" closeAccount: "Forigi konton" currentVersion: "Nuna versio" @@ -538,9 +585,10 @@ inUse: "Uzata" editCode: "Redakti kodon" emailNotification: "Sciigoj per retpoŝto" inChannelSearch: "Serĉi en kanalo" -useReactionPickerForContextMenu: "Malfermi reago-elektilon per dekstro-klaki" +useReactionPickerForContextMenu: "Dekstre-klaki por malfermi la elektilon de reagoj" typingUsers: "{users} nun skribas…" clear: "Vakigi" +markAllAsRead: "Marki ĉiujn kiel legito" goBack: "Reiri antaŭ" addDescription: "Priskribi" info: "Informoj" @@ -559,7 +607,7 @@ memo: "Memorigilo" high: "Alta" middle: "Meza" low: "Malalta" -customCss: "Uzantula CSS" +customCss: "Personecigita CSS" global: "Malloka" sent: "Sendi" received: "Ricevita" @@ -569,10 +617,27 @@ troubleshooting: "Problemsolvi" learnMore: "Lernu pli" translate: "Traduki" translatedFrom: "Tradukita el {x}" +itsOn: "Ŝaltita" +unread: "Nelegita" controlPanel: "Ŝaltpodio" classic: "Klasika" +ffVisibility: "Videbleco pri viaj sekvataro/sekvantaro\n" +ffVisibilityDescription: "Agordi la videblecon kiu povas vidi tiujn kiujn vi sekvas kaj tiujn kiuj sekvas vin." +continueThread: "Vidi pli mesaĝarojn" +incorrectPassword: "Nevalida pasvorto" +_emailUnavailable: + used: "La retpoŝto jam estas uzita." + format: "Nevalida formato." + disposable: "Dumtempa retpoŝto ne estas uzebla." + smtp: "Tiu retpoŝta servilo ne respondas" +_ffVisibility: + public: "Publika" + followers: "Afiŝi nur al sekvantoj" + private: "Malpublikigita" _signup: emailAddressInfo: "Entajpu vian retpoŝton" +_accountDelete: + accountDelete: "Forigi konton" _ad: back: "Nuligi" _forgotPassword: @@ -598,7 +663,7 @@ _aboutMisskey: contributors: "Precipaj kontribuantoj" allContributors: "Ĉiuj kontribuantoj" source: "Fontkodo" - translation: "Traduki Misskey'on" + translation: "Traduki Misskey" patrons: "Mecenatoj" _mfm: dummy: "Misskey evoluigas la mondon de Fediverso" @@ -614,19 +679,21 @@ _mfm: inlineMath: "Formulo (en linio)" blockMath: "Formulo (bloko)" quote: "Citi" - emoji: "Personecigitaj emoĵioj" search: "Serĉi" flip: "Inversa" x2: "Granda" x3: "Grandega" x4: "Pli grandega" font: "Presliteraro" + rotate: "Orientiĝo" _reversi: total: "Entute" _instanceTicker: none: "Ne montri" - remote: "Montri al transaj uzantoj" + remote: "Montri al foraj uzantoj" always: "Ĉiam montri" +_serverDisconnectedBehavior: + reload: "Aŭtomate reŝargi" _channel: create: "Krei kanalon" edit: "Redakti kanalon" @@ -640,13 +707,14 @@ _menuDisplay: hide: "Kaŝi" _wordMute: muteWords: "Silentigitaj vortoj" - soft: "En kliento" - hard: "En servilo" + soft: "Per la kliento" + hard: "Per la servilo" mutedNotes: "Silentigitaj notoj" _theme: manage: "Administri kolorarojn" code: "Kolorara kodo" description: "Priskribo" + defaultValue: "Implicitaĵa valoro" color: "Koloro" darken: "Malbrileco" lighten: "Brileco" @@ -657,7 +725,7 @@ _theme: hashtag: "Kradvorto" mention: "Mencioj" mentionMe: "Mencio al vi" - renote: "Noto plusendita" + renote: "Plusendita" buttonBg: "Fono de butono" driveFolderBg: "Fono de dosierujo de la disko" messageBg: "Fono de retbabilejo" @@ -688,7 +756,7 @@ _tutorial: title: "Uzado de Misskey" step1_1: "Bonvenon." step7_2: "Se vi volas scii pli pri Misskey, rigardu la fakon {help}." - step7_3: "Do, bonvolu amuziĝi Misskey'on🚀" + step7_3: "Do, bonvolu amuziĝi sur Misskey🚀" _2fa: registerKey: "Nove registri ŝlosilon" _permissions: @@ -732,10 +800,10 @@ _widgets: federation: "Federaĵo" slideshow: "Bildoprezento" button: "Butono" - onlineUsers: "Surkonektita uzanto" + onlineUsers: "Surkonektitaj uzantoj" aichan: "Ai" _cw: - show: "Vidu pli" + show: "Vidi pli" files: "{count} dosiero(j)" _poll: choiceN: "Balotilo {n}" @@ -747,15 +815,15 @@ _poll: closed: "Oni jam balotis ĝin" _visibility: public: "Publika" - publicDescription: "Via noto estos videbla de ĉiuj uzantoj" + publicDescription: "Afiŝi al ĉiuj en la Fediverso" home: "Hejma" homeDescription: "Dissendi nur sur hejma templinio" followers: "Nur al sekvantoj" - followersDescription: "Publiki nur al viaj sekvantoj" + followersDescription: "Afiŝi nur al sekvantoj" specified: "Rekte" - specifiedDescription: "Montri nur al specifaj uzantoj" + specifiedDescription: "Afiŝi nur al specifaj uzantoj" localOnly: "Nur loka" - localOnlyDescription: "Ne montri al transaj uzantoj" + localOnlyDescription: "Ne afiŝi al foraj uzantoj" _postForm: replyPlaceholder: "Respondi la noton…" quotePlaceholder: "Citi la noton…" @@ -789,7 +857,7 @@ _rooms: translate: "Movi" chooseImage: "Elekti bildon" _roomType: - default: "Defaŭlta" + default: "Implicitaĵo" _furnitures: bed: "Lito" low-table: "Malaltotablo" @@ -835,18 +903,22 @@ _pages: textInput: "Enmeto el teksto" _textInput: text: "Titolo" + default: "Implicitaĵa valoro" textareaInput: "Enmeto el teksto en multaj linioj" _textareaInput: text: "Titolo" + default: "Implicitaĵa valoro" numberInput: "Nombra enmeto" _numberInput: text: "Titolo" + default: "Implicitaĵa valoro" _canvas: id: "Kanvasa identigilo" _note: id: "Identigilo de noto" _switch: text: "Titolo" + default: "Implicitaĵa valoro" _counter: text: "Titolo" _button: @@ -856,6 +928,7 @@ _pages: event: "Nomo de la evento" _radioButton: title: "Titolo" + default: "Implicitaĵa valoro" script: categories: text: "Manipulo de teksto" @@ -874,6 +947,7 @@ _pages: arg1: "Teksto" _join: arg1: "Listoj" + arg2: "apartigilo" _randomPick: arg1: "Listoj" _dailyRandomPick: @@ -904,6 +978,7 @@ _pages: _relayStatus: requesting: "Atendado de aprobon" accepted: "Konfirmita" + rejected: "Malakceptita" _notification: fileUploaded: "La dosiero sukcese alŝutiĝis." youGotMention: "{name} mencis" @@ -918,13 +993,13 @@ _notification: yourFollowRequestAccepted: "Via peto de sekvado estis akceptita." _types: all: "Ĉio" - follow: "Nova sekvatoj" + follow: "Novaj sekvatoj" mention: "Mencioj" reply: "Respondoj" - renote: "Notoj plusenditaj" + renote: "Plusendoj" quote: "Citi" reaction: "Reagoj" - receiveFollowRequest: "Ricevita peton de sekvado" + receiveFollowRequest: "Ricevi peton de sekvado" followRequestAccepted: "Akceptita peto por sekvado" _deck: profile: "Agordaro" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 3421c64389..f81c3772aa 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -737,6 +737,7 @@ pubSub: "Cuentas Pub/Sub" lastCommunication: "Última comunicación" resolved: "Resuelto" unresolved: "Sin resolver" +controlPanel: "Panel de control" _accountDelete: accountDelete: "Eliminar Cuenta" _ad: @@ -767,6 +768,7 @@ _mfm: flip: "Echar de un capirotazo" flipDescription: "Voltea el contenido hacia arriba / abajo o hacia la izquierda / derecha." font: "Fuente" + rotate: "Rotar" _reversi: reversi: "Reversi" gameSettings: "Configuración del juego" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 5d67b5269a..cf5e2238b1 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -919,6 +919,7 @@ _mfm: rainbowDescription: "Permet d'afficher le contenu en couleurs arc-en-ciel." sparkle: "Paillettes" sparkleDescription: "Ajoute un effet scintillant au contenu." + rotate: "Pivoter" _reversi: reversi: "Reversi" gameSettings: "Réglages de la partie" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index f4997e3a64..d9e6368c3a 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -806,6 +806,10 @@ muteThread: "Bisukan thread" unmuteThread: "Suarakan thread" ffVisibility: "Visibilitas Mengikuti/Pengikut" ffVisibilityDescription: "Mengatur siapa yang dapat melihat pengikutmu dan yang kamu ikuti." +continueThread: "Lihat lanjutan thread" +deleteAccountConfirm: "Akun akan dihapus. Apakah kamu yakin?" +incorrectPassword: "Kata sandi salah." +voteConfirm: "Konfirmasi suara kamu untuk ({choice})?" _emailUnavailable: used: "Alamat surel ini telah digunakan" format: "Format tidak valid." @@ -929,6 +933,8 @@ _mfm: rainbowDescription: "Membuat konten muncul dalam warna pelangi." sparkle: "Kelap-kelip" sparkleDescription: "Memberikan konten efek partikel kelap-kelip." + rotate: "Putar" + rotateDescription: "Putar konten sesuai sudut yang ditentukan." _reversi: reversi: "Reversi" gameSettings: "Pengaturan permainan" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index fc032e068c..d650f44357 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -806,6 +806,7 @@ _mfm: font: "Tipo di carattere" fontDescription: "Puoi scegliere il tipo di carattere per il contenuto." rainbow: "Arcobaleno" + rotate: "Ruota" _reversi: reversi: "Reversi" gameSettings: "Impostazioni di gioco" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9877248eb3..d5c009bbcf 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -792,6 +792,7 @@ pubSub: "Pub/Subのアカウント" lastCommunication: "直近の通信" resolved: "解決済み" unresolved: "未解決" +breakFollow: "フォロワーを解除" itsOn: "オンになっています" itsOff: "オフになっています" emailRequiredForSignup: "アカウント登録にメールアドレスを必須にする" @@ -808,6 +809,8 @@ ffVisibility: "つながりの公開範囲" ffVisibilityDescription: "自分のフォロー/フォロワー情報の公開範囲を設定できます。" continueThread: "さらにスレッドを見る" deleteAccountConfirm: "アカウントが削除されます。よろしいですか?" +incorrectPassword: "パスワードが間違っています。" +voteConfirm: "「{choice}」に投票しますか?" _emailUnavailable: used: "既に使用されています" @@ -823,7 +826,7 @@ _ffVisibility: _signup: almostThere: "ほとんど完了です" - emailAddressInfo: "あなたが使っているメールアドレスを入力してください。" + emailAddressInfo: "あなたが使っているメールアドレスを入力してください。メールアドレスが公開されることはありません。" emailSent: "入力されたメールアドレス({email})宛に確認のメールが送信されました。メールに記載されたリンクにアクセスすると、アカウントの作成が完了します。" _accountDelete: @@ -944,6 +947,8 @@ _mfm: rainbowDescription: "内容をレインボーにします。" sparkle: "キラキラ" sparkleDescription: "キラキラしたパーティクルのエフェクトを追加します。" + rotate: "回転" + rotateDescription: "指定した角度で回転させます。" _reversi: reversi: "リバーシ" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index b73be17035..49ef286a59 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -700,6 +700,7 @@ _mfm: spin: "アニメーション(回転)" blur: "ぼかし" font: "フォント" + rotate: "回転" _reversi: reversi: "リバーシ" gameSettings: "対局の設定" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 10a9b6e3e1..dde60c4c81 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -899,6 +899,7 @@ _mfm: rainbowDescription: "내용을 무지개로 표시합니다." sparkle: "반짝반짝" sparkleDescription: "반짝이는 파티클 효과를 추가합니다." + rotate: "회전" _reversi: reversi: "리버시" gameSettings: "대국 설정" diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index 7a3c568f6f..0393d94303 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -1,5 +1,193 @@ --- _lang_: "Nederlands" headlineMisskey: "Netwerk verbonden door notities" +introMisskey: "Welkom! Misskey is een open source, gedecentraliseerde microblogdienst.\nMaak \"notities\" om je gedachten te delen met iedereen om je heen. 📡\nMet \"reacties\" kun je ook snel je mening geven over berichten van anderen. 👍\nLaten we een nieuwe wereld verkennen! 🚀" +monthAndDay: "{day} {month}" +search: "Zoeken" +notifications: "Meldingen" +username: "Gebruikersnaam" +password: "Wachtwoord" +forgotPassword: "Wachtwoord vergeten" +fetchingAsApObject: "Ophalen vanuit de Fediverse" +ok: "Ok" +gotIt: "Begrepen" +cancel: "Annuleren" +enterUsername: "Voer een gebruikersnaam in" +renotedBy: "Hergedeeld door {user}" +noNotes: "Geen notities" +noNotifications: "Geen meldingen" +instance: "Server" +settings: "Instellingen" +basicSettings: "Basisinstellingen" +otherSettings: "Overige instellingen" +openInWindow: "In een venster openen" +profile: "Profiel" +timeline: "Tijdlijn" +noAccountDescription: "Deze gebruiker heeft nog geen bio geschreven" +login: "Inloggen" +loggingIn: "Aan het inloggen" +logout: "Afmelden" +signup: "Registreren" +uploading: "Bezig met uploaden" +save: "Opslaan" +users: "Gebruikers" +addUser: "Toevoegen gebruiker" +favorite: "Favorieten" +favorites: "Toevoegen aan favorieten" +unfavorite: "Verwijderen uit favorieten" +favorited: "Toegevoegd aan favorieten." +alreadyFavorited: "Al toegevoegd aan favorieten" +cantFavorite: "Kon niet toevoegen aan favorieten" +pin: "Vastmaken aan profielpagina" +unpin: "Losmaken van profielpagina" +copyContent: "Kopiëren inhoud" +copyLink: "Kopiëren link" +delete: "Verwijderen" +deleteAndEdit: "Verwijderen en bewerken" +deleteAndEditConfirm: "Weet je zeker dat je deze notitie wilt verwijderen en dan bewerken? Je verliest alle reacties, herdelingen en antwoorden erop." +addToList: "Aan lijst toevoegen" +sendMessage: "Verstuur bericht" +copyUsername: "Kopiëren gebruikersnaam " +searchUser: "Zoeken een gebruiker" +reply: "Antwoord" +loadMore: "Laad meer" +showMore: "Toon meer" +youGotNewFollower: "volgde jou" +receiveFollowRequest: "Volgverzoek ontvangen" +followRequestAccepted: "Volgverzoek geaccepteerd" +mention: "Vermelding" +mentions: "Vermeldingen" +directNotes: "Directe notities" +importAndExport: "Import / export" +import: "Import" +export: "Export" +files: "Bestanden" +download: "Downloaden" +driveFileDeleteConfirm: "Weet je zeker dat je het bestand \"{name}\" wilt verwijderen? Notities met dit bestand als bijlage worden ook verwijderd." +unfollowConfirm: "Weet je zeker dat je {name} wilt ontvolgen?" +exportRequested: "Je hebt een export aangevraagd. Dit kan een tijdje duren. Het wordt toegevoegd aan je Drive zodra het is voltooid." +importRequested: "Je hebt een import aangevraagd. Dit kan even duren." +lists: "Lijsten" +noLists: "Je hebt geen lijsten" +note: "Notitie" +notes: "Notities" +following: "Volgend" +followers: "Volgers" +followsYou: "Volgt jou" +createList: "Creëer lijst" +manageLists: "Beheren lijsten" +error: "Fout" +somethingHappened: "Er is iets misgegaan." +retry: "Probeer opnieuw" +pageLoadError: "Pagina laden mislukt" +pageLoadErrorDescription: "Dit wordt normaal gesproken veroorzaakt door netwerkfouten of door de cache van de browser. Probeer de cache te wissen en probeer het na een tijdje wachten opnieuw." +serverIsDead: "De server reageert niet. Wacht even en probeer het opnieuw." +youShouldUpgradeClient: "Werk je client bij om deze pagina te zien." +enterListName: "Voer de naam van de lijst in" +privacy: "Privacy" +makeFollowManuallyApprove: "Volgverzoeken vergen een goedkeuring" +defaultNoteVisibility: "Standaard zichtbaarheid" +follow: "Volgen" +followRequest: "Verzoek om te mogen volgen" +followRequests: "Volgverzoeken" +unfollow: "Ontvolgen" +followRequestPending: "Wachten op goedkeuring volgverzoek" +enterEmoji: "Voer een emoji in" +renote: "Herdelen" +unrenote: "Stop herdelen" +renoted: "Herdeeld" +cantRenote: "Dit bericht kan niet worden herdeeld" +cantReRenote: "Een herdeling kan niet worden herdeeld" +quote: "Quote" +pinnedNote: "Vastgemaakte notitie" +pinned: "Vastmaken aan profielpagina" +you: "Jij" +clickToShow: "Klik om te bekijken" +sensitive: "NSFW" +add: "Toevoegen" +reaction: "Reacties" +reactionSettingDescription: "Configureer welke reacties je wilt weergeven in de reactiekiezer." +reactionSettingDescription2: "Sleep om opnieuw te ordenen, Klik om te verwijderen, Druk op \"+\" om toe te voegen" +rememberNoteVisibility: "Vergeet niet de notitie zichtbaarheidsinstellingen" +attachCancel: "Verwijder bijlage" +markAsSensitive: "Markeren als NSFW" +unmarkAsSensitive: "Geen NSFW" +enterFileName: "Invoeren bestandsnaam" +mute: "Dempen" +unmute: "Stop dempen" +block: "Blokkeren" +unblock: "Deblokkeren" +suspend: "Opschorten" +unsuspend: "Heractiveren" +blockConfirm: "Weet je zeker dat je dit account wil blokkeren?" +instances: "Server" +remove: "Verwijderen" +nsfw: "NSFW" +pinnedNotes: "Vastgemaakte notitie" +userList: "Lijsten" +smtpUser: "Gebruikersnaam" +smtpPass: "Wachtwoord" +user: "Gebruikers" muteThread: "Discussies dempen " unmuteThread: "Dempen van discussie ongedaan maken" +_email: + _follow: + title: "volgde jou" +_mfm: + mention: "Vermelding" + quote: "Quote" + search: "Zoeken" +_theme: + keys: + mention: "Vermelding" + renote: "Herdelen" +_sfx: + note: "Notities" + notification: "Meldingen" +_widgets: + notifications: "Meldingen" + timeline: "Tijdlijn" +_cw: + show: "Laad meer" +_visibility: + followers: "Volgers" +_profile: + username: "Gebruikersnaam" +_exportOrImport: + followingList: "Volgend" + muteList: "Dempen" + blockingList: "Blokkeren" + userLists: "Lijsten" +_pages: + script: + categories: + list: "Lijsten" + blocks: + _join: + arg1: "Lijsten" + _randomPick: + arg1: "Lijsten" + _dailyRandomPick: + arg1: "Lijsten" + _seedRandomPick: + arg2: "Lijsten" + _pick: + arg1: "Lijsten" + _listLen: + arg1: "Lijsten" + types: + array: "Lijsten" +_notification: + youWereFollowed: "volgde jou" + _types: + follow: "Volgend" + mention: "Vermelding" + renote: "Herdelen" + quote: "Quote" + reaction: "Reacties" +_deck: + _columns: + notifications: "Meldingen" + tl: "Tijdlijn" + list: "Lijsten" + mentions: "Vermeldingen" diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 5e1fba8382..1a52f35235 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -815,6 +815,7 @@ _mfm: blur: "Rozmycie" font: "Czcionka" fontDescription: "Wybiera czcionkę do wyświetlania treści." + rotate: "Obróć" _reversi: reversi: "Reversi" gameSettings: "Ustawienia gry" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index c46f02f102..d095887bdc 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -1,22 +1,33 @@ --- _lang_: "Português" +headlineMisskey: "Rede conectada por notas" monthAndDay: "{day}/{month}" search: "Pesquisar" notifications: "Notificações" username: "Nome de usuário" password: "Senha" +forgotPassword: "Esqueci a senha" +fetchingAsApObject: "Buscando no Fediverso" ok: "OK" gotIt: "Entendi" cancel: "Cancelar" enterUsername: "Digite o nome de usuário" renotedBy: "Repostado por {user}" noNotes: "Sem posts" +noNotifications: "Sem notificações" +instance: "Instância" settings: "Configurações" basicSettings: "Configurações básicas" otherSettings: "Outras configurações" +openInWindow: "Abrir numa janela" profile: "Perfil" timeline: "Timeline" +login: "Iniciar sessão" +loggingIn: "Iniciando sessão…" logout: "Sair" +signup: "Registrar-se" +uploading: "Enviando…" +save: "Guardar" users: "Usuários" favorite: "Favoritar" favorites: "Favoritar" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 1eb6dff0ef..1d889866db 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -922,6 +922,7 @@ _mfm: rainbowDescription: "Заставлять содержимое отображаться в цветах радуги." sparkle: "Блеск" sparkleDescription: "Добавьте эффект искрящихся частиц." + rotate: "Повернуть" _reversi: reversi: "Реверси" gameSettings: "Настройки игры" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 73f43669af..9104b0839d 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -771,6 +771,7 @@ _mfm: blurDescription: "Цей ефект зробить контент розмитим. Контент можна зробити чітким, якщо навести на нього вказівник миші." font: "Шрифт" fontDescription: "Встановлює шрифт для контенту." + rotate: "Обертати" _reversi: reversi: "Реверсі" gameSettings: "Налаштування гри" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 604f1e74d8..829c47e7dc 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -792,6 +792,7 @@ pubSub: "Pub/Sub账户" lastCommunication: "最近通信" resolved: "已解决" unresolved: "未解决" +breakFollow: "移除关注者" itsOn: "已开启" itsOff: "已关闭" emailRequiredForSignup: "注册账户需要电子邮件地址" @@ -808,6 +809,8 @@ ffVisibility: "连接的可见范围" ffVisibilityDescription: "您可以设置您的关注/关注者信息的公开范围" continueThread: "查看更多帖子" deleteAccountConfirm: "将要删除账户。是否确认?" +incorrectPassword: "密码错误" +voteConfirm: "确定投给“{choice}” ?" _emailUnavailable: used: "已经被使用过" format: "无效的格式" @@ -931,6 +934,8 @@ _mfm: rainbowDescription: "用彩虹色来显示内容。" sparkle: "闪光" sparkleDescription: "添加发光粒子效果。" + rotate: "旋转" + rotateDescription: "旋转指定的角度。" _reversi: reversi: "黑白棋" gameSettings: "对局设置" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 888e12490a..56eaaa0f0d 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -840,6 +840,7 @@ _mfm: blur: "模糊" font: "字型" fontDescription: "您可以設定顯示內容的字型" + rotate: "旋轉" _reversi: reversi: "黑白棋" gameSettings: "對弈設定" diff --git a/package.json b/package.json index 343e3f36cc..ef08f2d5e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "12.97.1", + "version": "12.98.0", "codename": "indigo", "repository": { "type": "git", @@ -46,7 +46,7 @@ "@types/fluent-ffmpeg": "2.1.17", "@typescript-eslint/parser": "5.4.0", "cross-env": "7.0.3", - "cypress": "9.0.0", + "cypress": "9.1.0", "start-server-and-test": "1.14.0", "typescript": "4.5.2" } diff --git a/packages/backend/src/misc/get-file-info.ts b/packages/backend/src/misc/get-file-info.ts index 39ba541395..8d7f6b1bf9 100644 --- a/packages/backend/src/misc/get-file-info.ts +++ b/packages/backend/src/misc/get-file-info.ts @@ -19,6 +19,7 @@ export type FileInfo = { }; width?: number; height?: number; + orientation?: number; blurhash?: string; warnings: string[]; }; @@ -47,6 +48,7 @@ export async function getFileInfo(path: string): Promise { // image dimensions let width: number | undefined; let height: number | undefined; + let orientation: number | undefined; if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/bmp', 'image/tiff', 'image/svg+xml', 'image/vnd.adobe.photoshop'].includes(type.mime)) { const imageSize = await detectImageSize(path).catch(e => { @@ -61,6 +63,7 @@ export async function getFileInfo(path: string): Promise { } else if (imageSize.wUnits === 'px') { width = imageSize.width; height = imageSize.height; + orientation = imageSize.orientation; // 制限を超えている画像は octet-stream にする if (imageSize.width > 16383 || imageSize.height > 16383) { @@ -87,6 +90,7 @@ export async function getFileInfo(path: string): Promise { type, width, height, + orientation, blurhash, warnings, }; @@ -163,6 +167,7 @@ async function detectImageSize(path: string): Promise<{ height: number; wUnits: string; hUnits: string; + orientation?: number; }> { const readable = fs.createReadStream(path); const imageSize = await probeImageSize(readable); diff --git a/packages/backend/src/models/entities/drive-file.ts b/packages/backend/src/models/entities/drive-file.ts index 698dfac222..4ec7b94ed2 100644 --- a/packages/backend/src/models/entities/drive-file.ts +++ b/packages/backend/src/models/entities/drive-file.ts @@ -77,7 +77,7 @@ export class DriveFile { default: {}, comment: 'The any properties of the DriveFile. For example, it includes image width/height.' }) - public properties: { width?: number; height?: number; avgColor?: string }; + public properties: { width?: number; height?: number; orientation?: number; avgColor?: string }; @Index() @Column('boolean') diff --git a/packages/backend/src/models/repositories/drive-file.ts b/packages/backend/src/models/repositories/drive-file.ts index ddf9a46afd..f2f0308dc0 100644 --- a/packages/backend/src/models/repositories/drive-file.ts +++ b/packages/backend/src/models/repositories/drive-file.ts @@ -28,6 +28,19 @@ export class DriveFileRepository extends Repository { ); } + public getPublicProperties(file: DriveFile): DriveFile['properties'] { + if (file.properties.orientation != null) { + const properties = JSON.parse(JSON.stringify(file.properties)); + if (file.properties.orientation >= 5) { + [properties.width, properties.height] = [properties.height, properties.width]; + } + properties.orientation = undefined; + return properties; + } + + return file.properties; + } + public getPublicUrl(file: DriveFile, thumbnail = false, meta?: Meta): string | null { // リモートかつメディアプロキシ if (file.uri != null && file.userHost != null && config.mediaProxy != null) { @@ -122,7 +135,7 @@ export class DriveFileRepository extends Repository { size: file.size, isSensitive: file.isSensitive, blurhash: file.blurhash, - properties: file.properties, + properties: opts.self ? file.properties : this.getPublicProperties(file), url: opts.self ? file.url : this.getPublicUrl(file, false, meta), thumbnailUrl: this.getPublicUrl(file, true, meta), comment: file.comment, @@ -202,6 +215,11 @@ export const packedDriveFileSchema = { optional: true as const, nullable: false as const, example: 720 }, + orientation: { + type: 'number' as const, + optional: true as const, nullable: false as const, + example: 8 + }, avgColor: { type: 'string' as const, optional: true as const, nullable: false as const, diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index fc0860970c..81468d6de2 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -189,12 +189,12 @@ export class UserRepository extends Repository { const followingCount = profile == null ? null : (profile.ffVisibility === 'public') || (meId === user.id) ? user.followingCount : - (profile.ffVisibility === 'followers') && (relation!.isFollowing) ? user.followingCount : + (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount : null; const followersCount = profile == null ? null : (profile.ffVisibility === 'public') || (meId === user.id) ? user.followersCount : - (profile.ffVisibility === 'followers') && (relation!.isFollowing) ? user.followersCount : + (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : null; const falsy = opts.detail ? false : undefined; diff --git a/packages/backend/src/remote/activitypub/kernel/reject/follow.ts b/packages/backend/src/remote/activitypub/kernel/reject/follow.ts index 356547440f..049437b18f 100644 --- a/packages/backend/src/remote/activitypub/kernel/reject/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/reject/follow.ts @@ -1,8 +1,9 @@ import { IRemoteUser } from '@/models/entities/user'; -import reject from '@/services/following/requests/reject'; +import { remoteReject } from '@/services/following/reject'; import { IFollow } from '../../type'; import DbResolver from '../../db-resolver'; import { relayRejected } from '@/services/relay'; +import { Users } from '@/models'; export default async (actor: IRemoteUser, activity: IFollow): Promise => { // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある @@ -14,7 +15,7 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise => return `skip: follower not found`; } - if (follower.host != null) { + if (!Users.isLocalUser(follower)) { return `skip: follower is not a local user`; } @@ -24,6 +25,6 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise => return await relayRejected(match[1]); } - await reject(actor, follower); + await remoteReject(actor, follower); return `ok`; }; diff --git a/packages/backend/src/remote/activitypub/kernel/undo/accept.ts b/packages/backend/src/remote/activitypub/kernel/undo/accept.ts new file mode 100644 index 0000000000..5112d1d4ea --- /dev/null +++ b/packages/backend/src/remote/activitypub/kernel/undo/accept.ts @@ -0,0 +1,27 @@ +import unfollow from '@/services/following/delete'; +import cancelRequest from '@/services/following/requests/cancel'; +import {IAccept} from '../../type'; +import { IRemoteUser } from '@/models/entities/user'; +import { Followings } from '@/models/index'; +import DbResolver from '../../db-resolver'; + +export default async (actor: IRemoteUser, activity: IAccept): Promise => { + const dbResolver = new DbResolver(); + + const follower = await dbResolver.getUserFromApId(activity.object); + if (follower == null) { + return `skip: follower not found`; + } + + const following = await Followings.findOne({ + followerId: follower.id, + followeeId: actor.id + }); + + if (following) { + await unfollow(follower, actor); + return `ok: unfollowed`; + } + + return `skip: フォローされていない`; +}; diff --git a/packages/backend/src/remote/activitypub/kernel/undo/index.ts b/packages/backend/src/remote/activitypub/kernel/undo/index.ts index 14b1add152..8de78420e3 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/index.ts @@ -1,8 +1,9 @@ import { IRemoteUser } from '@/models/entities/user'; -import { IUndo, isFollow, isBlock, isLike, isAnnounce, getApType } from '../../type'; +import {IUndo, isFollow, isBlock, isLike, isAnnounce, getApType, isAccept} from '../../type'; import unfollow from './follow'; import unblock from './block'; import undoLike from './like'; +import undoAccept from './accept'; import { undoAnnounce } from './announce'; import Resolver from '../../resolver'; import { apLogger } from '../../logger'; @@ -29,6 +30,7 @@ export default async (actor: IRemoteUser, activity: IUndo): Promise => { if (isBlock(object)) return await unblock(actor, object); if (isLike(object)) return await undoLike(actor, object); if (isAnnounce(object)) return await undoAnnounce(actor, object); + if (isAccept(object)) return await undoAccept(actor, object); return `skip: unknown object type ${getApType(object)}`; }; diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 1759e95b4c..02fec2778b 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -33,6 +33,14 @@ export const meta = { untilId: { validator: $.optional.type(ID), }, + + sinceDate: { + validator: $.optional.num, + }, + + untilDate: { + validator: $.optional.num, + }, }, errors: { @@ -68,7 +76,8 @@ export default define(meta, async (ps, user) => { .select('joining.noteId') .where('joining.antennaId = :antennaId', { antennaId: antenna.id }); - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) + const query = makePaginationQuery(Notes.createQueryBuilder('note'), + ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere(`note.id IN (${ antennaQuery.getQuery() })`) .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') diff --git a/packages/backend/src/server/api/endpoints/following/invalidate.ts b/packages/backend/src/server/api/endpoints/following/invalidate.ts new file mode 100644 index 0000000000..c0e9df3652 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/following/invalidate.ts @@ -0,0 +1,82 @@ +import $ from 'cafy'; +import { ID } from '@/misc/cafy-id'; +import * as ms from 'ms'; +import deleteFollowing from '@/services/following/delete'; +import define from '../../define'; +import { ApiError } from '../../error'; +import { getUser } from '../../common/getters'; +import { Followings, Users } from '@/models/index'; + +export const meta = { + tags: ['following', 'users'], + + limit: { + duration: ms('1hour'), + max: 100 + }, + + requireCredential: true as const, + + kind: 'write:following', + + params: { + userId: { + validator: $.type(ID), + } + }, + + errors: { + noSuchUser: { + message: 'No such user.', + code: 'NO_SUCH_USER', + id: '5b12c78d-2b28-4dca-99d2-f56139b42ff8' + }, + + followerIsYourself: { + message: 'Follower is yourself.', + code: 'FOLLOWER_IS_YOURSELF', + id: '07dc03b9-03da-422d-885b-438313707662' + }, + + notFollowing: { + message: 'The other use is not following you.', + code: 'NOT_FOLLOWING', + id: '5dbf82f5-c92b-40b1-87d1-6c8c0741fd09' + }, + }, + + res: { + type: 'object' as const, + optional: false as const, nullable: false as const, + ref: 'User' + } +}; + +export default define(meta, async (ps, user) => { + const followee = user; + + // Check if the follower is yourself + if (user.id === ps.userId) { + throw new ApiError(meta.errors.followerIsYourself); + } + + // Get follower + const follower = await getUser(ps.userId).catch(e => { + if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + throw e; + }); + + // Check not following + const exist = await Followings.findOne({ + followerId: follower.id, + followeeId: followee.id + }); + + if (exist == null) { + throw new ApiError(meta.errors.notFollowing); + } + + await deleteFollowing(follower, followee); + + return await Users.pack(followee.id, user); +}); diff --git a/packages/backend/src/server/api/endpoints/following/requests/reject.ts b/packages/backend/src/server/api/endpoints/following/requests/reject.ts index 620324361f..30d0e094c3 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/reject.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/reject.ts @@ -1,6 +1,6 @@ import $ from 'cafy'; import { ID } from '@/misc/cafy-id'; -import rejectFollowRequest from '@/services/following/requests/reject'; +import { rejectFollowRequest } from '@/services/following/reject'; import define from '../../../define'; import { ApiError } from '../../../error'; import { getUser } from '../../../common/getters'; diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index 6c5fefd4ad..a57f9cf068 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -372,12 +372,16 @@ export default async function( const properties: { width?: number; height?: number; + orientation?: number; } = {}; if (info.width) { properties['width'] = info.width; properties['height'] = info.height; } + if (info.orientation != null) { + properties['orientation'] = info.orientation; + } const profile = user ? await UserProfiles.findOne(user.id) : null; diff --git a/packages/backend/src/services/following/delete.ts b/packages/backend/src/services/following/delete.ts index 29e3372b6a..ea612147df 100644 --- a/packages/backend/src/services/following/delete.ts +++ b/packages/backend/src/services/following/delete.ts @@ -2,6 +2,7 @@ import { publishMainStream, publishUserEvent } from '@/services/stream'; import { renderActivity } from '@/remote/activitypub/renderer/index'; import renderFollow from '@/remote/activitypub/renderer/follow'; import renderUndo from '@/remote/activitypub/renderer/undo'; +import renderReject from '@/remote/activitypub/renderer/reject'; import { deliver } from '@/queue/index'; import Logger from '../logger'; import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; @@ -40,6 +41,12 @@ export default async function(follower: { id: User['id']; host: User['host']; ur const content = renderActivity(renderUndo(renderFollow(follower, followee), follower)); deliver(follower, content, followee.inbox); } + + if (Users.isLocalUser(followee) && Users.isRemoteUser(follower)) { + // local user has null host + const content = renderActivity(renderReject(renderFollow(follower, followee), followee)); + deliver(followee, content, follower.inbox); + } } export async function decrementFollowing(follower: { id: User['id']; host: User['host']; }, followee: { id: User['id']; host: User['host']; }) { diff --git a/packages/backend/src/services/following/reject.ts b/packages/backend/src/services/following/reject.ts new file mode 100644 index 0000000000..0ec4d7d00c --- /dev/null +++ b/packages/backend/src/services/following/reject.ts @@ -0,0 +1,105 @@ +import { renderActivity } from '@/remote/activitypub/renderer/index'; +import renderFollow from '@/remote/activitypub/renderer/follow'; +import renderReject from '@/remote/activitypub/renderer/reject'; +import { deliver } from '@/queue/index'; +import { publishMainStream, publishUserEvent } from '@/services/stream'; +import { User, ILocalUser, IRemoteUser } from '@/models/entities/user'; +import { Users, FollowRequests, Followings } from '@/models/index'; +import { decrementFollowing } from './delete'; + +type Local = ILocalUser | { id: User['id']; host: User['host']; uri: User['host'] }; +type Remote = IRemoteUser; +type Both = Local | Remote; + +/** + * API following/request/reject + */ +export async function rejectFollowRequest(user: Local, follower: Both) { + if (Users.isRemoteUser(follower)) { + deliverReject(user, follower); + } + + await removeFollowRequest(user, follower); + + if (Users.isLocalUser(follower)) { + publishUnfollow(user, follower); + } +} + +/** + * API following/reject + */ +export async function rejectFollow(user: Local, follower: Both) { + if (Users.isRemoteUser(follower)) { + deliverReject(user, follower); + } + + await removeFollow(user, follower); + + if (Users.isLocalUser(follower)) { + publishUnfollow(user, follower); + } +} + +/** + * AP Reject/Follow + */ +export async function remoteReject(actor: Remote, follower: Local) { + await removeFollowRequest(actor, follower); + await removeFollow(actor, follower); + publishUnfollow(actor, follower); +} + +/** + * Remove follow request record + */ +async function removeFollowRequest(followee: Both, follower: Both) { + const request = await FollowRequests.findOne({ + followeeId: followee.id, + followerId: follower.id + }); + + if (!request) return; + + await FollowRequests.delete(request.id); +} + +/** + * Remove follow record + */ +async function removeFollow(followee: Both, follower: Both) { + const following = await Followings.findOne({ + followeeId: followee.id, + followerId: follower.id + }); + + if (!following) return; + + await Followings.delete(following.id); + decrementFollowing(follower, followee); +} + +/** + * Deliver Reject to remote + */ +async function deliverReject(followee: Local, follower: Remote) { + const request = await FollowRequests.findOne({ + followeeId: followee.id, + followerId: follower.id + }); + + const content = renderActivity(renderReject(renderFollow(follower, followee, request?.requestId || undefined), followee)); + deliver(followee, content, follower.inbox); +} + +/** + * Publish unfollow to local + */ +async function publishUnfollow(followee: Both, follower: Local) { + const packedFollowee = await Users.pack(followee.id, follower, { + detail: true + }); + + publishUserEvent(follower.id, 'unfollow', packedFollowee); + publishMainStream(follower.id, 'unfollow', packedFollowee); +} diff --git a/packages/backend/src/services/following/requests/reject.ts b/packages/backend/src/services/following/requests/reject.ts deleted file mode 100644 index 41cebd9e41..0000000000 --- a/packages/backend/src/services/following/requests/reject.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderFollow from '@/remote/activitypub/renderer/follow'; -import renderReject from '@/remote/activitypub/renderer/reject'; -import { deliver } from '@/queue/index'; -import { publishMainStream, publishUserEvent } from '@/services/stream'; -import { User, ILocalUser } from '@/models/entities/user'; -import { Users, FollowRequests, Followings } from '@/models/index'; -import { decrementFollowing } from '../delete'; - -export default async function(followee: { id: User['id']; host: User['host']; uri: User['host'] }, follower: User) { - if (Users.isRemoteUser(follower) && Users.isLocalUser(followee)) { - const request = await FollowRequests.findOne({ - followeeId: followee.id, - followerId: follower.id - }); - - const content = renderActivity(renderReject(renderFollow(follower, followee, request!.requestId!), followee)); - deliver(followee, content, follower.inbox); - } - - const request = await FollowRequests.findOne({ - followeeId: followee.id, - followerId: follower.id - }); - - if (request) { - await FollowRequests.delete(request.id); - } else { - const following = await Followings.findOne({ - followeeId: followee.id, - followerId: follower.id - }); - - if (following) { - await Followings.delete(following.id); - decrementFollowing(follower, followee); - } - } - - Users.pack(followee.id, follower, { - detail: true - }).then(packed => { - publishUserEvent(follower.id, 'unfollow', packed); - publishMainStream(follower.id, 'unfollow', packed); - }); -} diff --git a/packages/backend/tools/accept-migration.ts b/packages/backend/src/tools/accept-migration.ts similarity index 100% rename from packages/backend/tools/accept-migration.ts rename to packages/backend/src/tools/accept-migration.ts diff --git a/packages/backend/tools/add-emoji.ts b/packages/backend/src/tools/add-emoji.ts similarity index 83% rename from packages/backend/tools/add-emoji.ts rename to packages/backend/src/tools/add-emoji.ts index 9ffe7dfa81..6c750bcab0 100644 --- a/packages/backend/tools/add-emoji.ts +++ b/packages/backend/src/tools/add-emoji.ts @@ -1,7 +1,10 @@ -import { Emojis } from '@/models/index'; +import { initDb } from '@/db/postgre'; import { genId } from '@/misc/gen-id'; async function main(name: string, url: string, alias?: string): Promise { + await initDb(); + const { Emojis } = await import('@/models/index'); + const aliases = alias != null ? [ alias ] : []; await Emojis.save({ diff --git a/packages/backend/tools/demote-admin.ts b/packages/backend/src/tools/demote-admin.ts similarity index 81% rename from packages/backend/tools/demote-admin.ts rename to packages/backend/src/tools/demote-admin.ts index d7c6d1cec2..b326c946ef 100644 --- a/packages/backend/tools/demote-admin.ts +++ b/packages/backend/src/tools/demote-admin.ts @@ -1,13 +1,11 @@ import { initDb } from '../db/postgre'; -import { getRepository } from 'typeorm'; -import { User } from '@/models/entities/user'; async function main(username: string) { if (!username) throw `username required`; username = username.replace(/^@/, ''); await initDb(); - const Users = getRepository(User); + const { Users } = await import('@/models/index'); const res = await Users.update({ usernameLower: username.toLowerCase(), diff --git a/packages/backend/tools/mark-admin.ts b/packages/backend/src/tools/mark-admin.ts similarity index 81% rename from packages/backend/tools/mark-admin.ts rename to packages/backend/src/tools/mark-admin.ts index 62ed0f09ee..0833f22266 100644 --- a/packages/backend/tools/mark-admin.ts +++ b/packages/backend/src/tools/mark-admin.ts @@ -1,13 +1,11 @@ import { initDb } from '../db/postgre'; -import { getRepository } from 'typeorm'; -import { User } from '@/models/entities/user'; async function main(username: string) { if (!username) throw `username required`; username = username.replace(/^@/, ''); await initDb(); - const Users = getRepository(User); + const { Users } = await import('@/models/index'); const res = await Users.update({ usernameLower: username.toLowerCase(), diff --git a/packages/backend/tools/refresh-question.ts b/packages/backend/src/tools/refresh-question.ts similarity index 63% rename from packages/backend/tools/refresh-question.ts rename to packages/backend/src/tools/refresh-question.ts index 98a3c2865f..3bbb781ae7 100644 --- a/packages/backend/tools/refresh-question.ts +++ b/packages/backend/src/tools/refresh-question.ts @@ -1,6 +1,9 @@ -import { updateQuestion } from '@/remote/activitypub/models/question'; +import { initDb } from '@/db/postgre'; async function main(uri: string): Promise { + await initDb(); + const { updateQuestion } = await import('@/remote/activitypub/models/question'); + return await updateQuestion(uri); } diff --git a/packages/backend/tools/resync-remote-user.ts b/packages/backend/src/tools/resync-remote-user.ts similarity index 100% rename from packages/backend/tools/resync-remote-user.ts rename to packages/backend/src/tools/resync-remote-user.ts diff --git a/packages/backend/tools/show-signin-history.ts b/packages/backend/src/tools/show-signin-history.ts similarity index 91% rename from packages/backend/tools/show-signin-history.ts rename to packages/backend/src/tools/show-signin-history.ts index ad92316314..1291a1b22f 100644 --- a/packages/backend/tools/show-signin-history.ts +++ b/packages/backend/src/tools/show-signin-history.ts @@ -1,4 +1,4 @@ -import { Users, Signins } from '@/models/index'; +import { initDb } from '@/db/postgre'; // node built/tools/show-signin-history username // => {Success} {Date} {IPAddrsss} @@ -10,6 +10,9 @@ import { Users, Signins } from '@/models/index'; // with full request headers async function main(username: string, headers?: string[]) { + await initDb(); + const { Users, Signins } = await import('@/models/index'); + const user = await Users.findOne({ host: null, usernameLower: username.toLowerCase(), diff --git a/packages/backend/test/get-file-info.ts b/packages/backend/test/get-file-info.ts index cc9eefbfc6..a0146bd815 100644 --- a/packages/backend/test/get-file-info.ts +++ b/packages/backend/test/get-file-info.ts @@ -17,6 +17,7 @@ describe('Get file info', () => { }, width: undefined, height: undefined, + orientation: undefined, }); })); @@ -34,6 +35,7 @@ describe('Get file info', () => { }, width: 512, height: 512, + orientation: undefined, }); })); @@ -51,6 +53,7 @@ describe('Get file info', () => { }, width: 256, height: 256, + orientation: undefined, }); })); @@ -68,6 +71,7 @@ describe('Get file info', () => { }, width: 256, height: 256, + orientation: undefined, }); })); @@ -85,6 +89,7 @@ describe('Get file info', () => { }, width: 256, height: 256, + orientation: undefined, }); })); @@ -102,6 +107,7 @@ describe('Get file info', () => { }, width: 256, height: 256, + orientation: undefined, }); })); @@ -120,6 +126,7 @@ describe('Get file info', () => { }, width: 256, height: 256, + orientation: undefined, }); })); @@ -137,6 +144,25 @@ describe('Get file info', () => { }, width: 25000, height: 25000, + orientation: undefined, + }); + })); + + it('Rotate JPEG', async (async () => { + const path = `${__dirname}/resources/rotate.jpg`; + const info = await getFileInfo(path) as any; + delete info.warnings; + delete info.blurhash; + assert.deepStrictEqual(info, { + size: 12624, + md5: '68d5b2d8d1d1acbbce99203e3ec3857e', + type: { + mime: 'image/jpeg', + ext: 'jpg' + }, + width: 512, + height: 256, + orientation: 8, }); })); }); diff --git a/packages/backend/test/resources/rotate.jpg b/packages/backend/test/resources/rotate.jpg new file mode 100644 index 0000000000..477c2baf5b Binary files /dev/null and b/packages/backend/test/resources/rotate.jpg differ diff --git a/packages/backend/tools/accept-migration.js b/packages/backend/tools/accept-migration.js deleted file mode 100644 index 309a4ab5e3..0000000000 --- a/packages/backend/tools/accept-migration.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -// ex) node built/tools/accept-migration Yo 1000000000001 -Object.defineProperty(exports, "__esModule", { value: true }); -const typeorm_1 = require("typeorm"); -const index_1 = require("@/config/index"); -(0, typeorm_1.createConnection)({ - type: 'postgres', - host: index_1.default.db.host, - port: index_1.default.db.port, - username: index_1.default.db.user, - password: index_1.default.db.pass, - database: index_1.default.db.db, - extra: index_1.default.db.extra, - synchronize: false, - dropSchema: false, -}).then(c => { - c.query(`INSERT INTO migrations(timestamp,name) VALUES (${process.argv[3]}, '${process.argv[2]}${process.argv[3]}');`).then(() => { - console.log('done'); - process.exit(0); - }).catch(e => { - console.log('ERROR:'); - console.log(e); - process.exit(1); - }); -}); -//# sourceMappingURL=accept-migration.js.map \ No newline at end of file diff --git a/packages/backend/tools/accept-migration.js.map b/packages/backend/tools/accept-migration.js.map deleted file mode 100644 index c158a49661..0000000000 --- a/packages/backend/tools/accept-migration.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"accept-migration.js","sourceRoot":"","sources":["accept-migration.ts"],"names":[],"mappings":";AAAA,yDAAyD;;AAEzD,qCAA2C;AAC3C,0CAAoC;AAEpC,IAAA,0BAAgB,EAAC;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,eAAM,CAAC,EAAE,CAAC,IAAI;IACpB,IAAI,EAAE,eAAM,CAAC,EAAE,CAAC,IAAI;IACpB,QAAQ,EAAE,eAAM,CAAC,EAAE,CAAC,IAAI;IACxB,QAAQ,EAAE,eAAM,CAAC,EAAE,CAAC,IAAI;IACxB,QAAQ,EAAE,eAAM,CAAC,EAAE,CAAC,EAAE;IACtB,KAAK,EAAE,eAAM,CAAC,EAAE,CAAC,KAAK;IACtB,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,KAAK;CACjB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;IACX,CAAC,CAAC,KAAK,CAAC,kDAAkD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;QAChI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACZ,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/backend/tools/add-emoji.js b/packages/backend/tools/add-emoji.js deleted file mode 100644 index df02f554a5..0000000000 --- a/packages/backend/tools/add-emoji.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const index_1 = require("@/models/index"); -const gen_id_1 = require("@/misc/gen-id"); -async function main(name, url, alias) { - const aliases = alias != null ? [alias] : []; - await index_1.Emojis.save({ - id: (0, gen_id_1.genId)(), - host: null, - name, - url, - aliases, - updatedAt: new Date() - }); -} -const args = process.argv.slice(2); -const name = args[0]; -const url = args[1]; -if (!name) - throw new Error('require name'); -if (!url) - throw new Error('require url'); -main(name, url).then(() => { - console.log('success'); - process.exit(0); -}).catch(e => { - console.warn(e); - process.exit(1); -}); -//# sourceMappingURL=add-emoji.js.map \ No newline at end of file diff --git a/packages/backend/tools/add-emoji.js.map b/packages/backend/tools/add-emoji.js.map deleted file mode 100644 index 03bf31b984..0000000000 --- a/packages/backend/tools/add-emoji.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"add-emoji.js","sourceRoot":"","sources":["add-emoji.ts"],"names":[],"mappings":";;AAAA,0CAAwC;AACxC,0CAAsC;AAEtC,KAAK,UAAU,IAAI,CAAC,IAAY,EAAE,GAAW,EAAE,KAAc;IAC5D,MAAM,OAAO,GAAG,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAE,KAAK,CAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/C,MAAM,cAAM,CAAC,IAAI,CAAC;QACjB,EAAE,EAAE,IAAA,cAAK,GAAE;QACX,IAAI,EAAE,IAAI;QACV,IAAI;QACJ,GAAG;QACH,OAAO;QACP,SAAS,EAAE,IAAI,IAAI,EAAE;KACrB,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACrB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAEpB,IAAI,CAAC,IAAI;IAAE,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;AAC3C,IAAI,CAAC,GAAG;IAAE,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;AAEzC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;IACzB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/backend/tools/demote-admin.js b/packages/backend/tools/demote-admin.js deleted file mode 100644 index d6a296883a..0000000000 --- a/packages/backend/tools/demote-admin.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const postgre_1 = require("../db/postgre"); -const typeorm_1 = require("typeorm"); -const user_1 = require("@/models/entities/user"); -async function main(username) { - if (!username) - throw `username required`; - username = username.replace(/^@/, ''); - await (0, postgre_1.initDb)(); - const Users = (0, typeorm_1.getRepository)(user_1.User); - const res = await Users.update({ - usernameLower: username.toLowerCase(), - host: null - }, { - isAdmin: false - }); - if (res.affected !== 1) { - throw 'Failed'; - } -} -const args = process.argv.slice(2); -main(args[0]).then(() => { - console.log('Success'); - process.exit(0); -}).catch(e => { - console.error(`Error: ${e.message || e}`); - process.exit(1); -}); -//# sourceMappingURL=demote-admin.js.map \ No newline at end of file diff --git a/packages/backend/tools/demote-admin.js.map b/packages/backend/tools/demote-admin.js.map deleted file mode 100644 index 4403e2bab0..0000000000 --- a/packages/backend/tools/demote-admin.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"demote-admin.js","sourceRoot":"","sources":["demote-admin.ts"],"names":[],"mappings":";;AAAA,2CAAuC;AACvC,qCAAwC;AACxC,iDAA8C;AAE9C,KAAK,UAAU,IAAI,CAAC,QAAgB;IACnC,IAAI,CAAC,QAAQ;QAAE,MAAM,mBAAmB,CAAC;IACzC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAEtC,MAAM,IAAA,gBAAM,GAAE,CAAC;IACf,MAAM,KAAK,GAAG,IAAA,uBAAa,EAAC,WAAI,CAAC,CAAC;IAElC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC;QAC9B,aAAa,EAAE,QAAQ,CAAC,WAAW,EAAE;QACrC,IAAI,EAAE,IAAI;KACV,EAAE;QACF,OAAO,EAAE,KAAK;KACd,CAAC,CAAC;IAEH,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,EAAE;QACvB,MAAM,QAAQ,CAAC;KACf;AACF,CAAC;AAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;IACvB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACZ,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/backend/tools/mark-admin.js b/packages/backend/tools/mark-admin.js deleted file mode 100644 index 4563d9c332..0000000000 --- a/packages/backend/tools/mark-admin.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const postgre_1 = require("../db/postgre"); -const typeorm_1 = require("typeorm"); -const user_1 = require("@/models/entities/user"); -async function main(username) { - if (!username) - throw `username required`; - username = username.replace(/^@/, ''); - await (0, postgre_1.initDb)(); - const Users = (0, typeorm_1.getRepository)(user_1.User); - const res = await Users.update({ - usernameLower: username.toLowerCase(), - host: null - }, { - isAdmin: true - }); - if (res.affected !== 1) { - throw 'Failed'; - } -} -const args = process.argv.slice(2); -main(args[0]).then(() => { - console.log('Success'); - process.exit(0); -}).catch(e => { - console.error(`Error: ${e.message || e}`); - process.exit(1); -}); -//# sourceMappingURL=mark-admin.js.map \ No newline at end of file diff --git a/packages/backend/tools/mark-admin.js.map b/packages/backend/tools/mark-admin.js.map deleted file mode 100644 index 5633e2f894..0000000000 --- a/packages/backend/tools/mark-admin.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mark-admin.js","sourceRoot":"","sources":["mark-admin.ts"],"names":[],"mappings":";;AAAA,2CAAuC;AACvC,qCAAwC;AACxC,iDAA8C;AAE9C,KAAK,UAAU,IAAI,CAAC,QAAgB;IACnC,IAAI,CAAC,QAAQ;QAAE,MAAM,mBAAmB,CAAC;IACzC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAEtC,MAAM,IAAA,gBAAM,GAAE,CAAC;IACf,MAAM,KAAK,GAAG,IAAA,uBAAa,EAAC,WAAI,CAAC,CAAC;IAElC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC;QAC9B,aAAa,EAAE,QAAQ,CAAC,WAAW,EAAE;QACrC,IAAI,EAAE,IAAI;KACV,EAAE;QACF,OAAO,EAAE,IAAI;KACb,CAAC,CAAC;IAEH,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,EAAE;QACvB,MAAM,QAAQ,CAAC;KACf;AACF,CAAC;AAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;IACvB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACZ,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/backend/tools/refresh-question.js b/packages/backend/tools/refresh-question.js deleted file mode 100644 index 0536c38207..0000000000 --- a/packages/backend/tools/refresh-question.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const question_1 = require("@/remote/activitypub/models/question"); -async function main(uri) { - return await (0, question_1.updateQuestion)(uri); -} -const args = process.argv.slice(2); -const uri = args[0]; -main(uri).then(result => { - console.log(`Done: ${result}`); -}).catch(e => { - console.warn(e); -}); -//# sourceMappingURL=refresh-question.js.map \ No newline at end of file diff --git a/packages/backend/tools/refresh-question.js.map b/packages/backend/tools/refresh-question.js.map deleted file mode 100644 index 3db6d0b8bb..0000000000 --- a/packages/backend/tools/refresh-question.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"refresh-question.js","sourceRoot":"","sources":["refresh-question.ts"],"names":[],"mappings":";;AAAA,mEAAsE;AAEtE,KAAK,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,MAAM,IAAA,yBAAc,EAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAEpB,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;IACvB,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/backend/tools/resync-remote-user.js b/packages/backend/tools/resync-remote-user.js deleted file mode 100644 index 05d76ecc97..0000000000 --- a/packages/backend/tools/resync-remote-user.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const postgre_1 = require("@/db/postgre"); -const Acct = require("misskey-js/built/acct"); -async function main(acct) { - await (0, postgre_1.initDb)(); - const { resolveUser } = await Promise.resolve().then(() => require('@/remote/resolve-user')); - const { username, host } = Acct.parse(acct); - await resolveUser(username, host, {}, true); -} -// get args -const args = process.argv.slice(2); -let acct = args[0]; -// normalize args -acct = acct.replace(/^@/, ''); -// check args -if (!acct.match(/^\w+@\w/)) { - throw `Invalid acct format. Valid format are user@host`; -} -console.log(`resync ${acct}`); -main(acct).then(() => { - console.log('Done'); -}).catch(e => { - console.warn(e); -}); -//# sourceMappingURL=resync-remote-user.js.map \ No newline at end of file diff --git a/packages/backend/tools/resync-remote-user.js.map b/packages/backend/tools/resync-remote-user.js.map deleted file mode 100644 index 456d7da1d1..0000000000 --- a/packages/backend/tools/resync-remote-user.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"resync-remote-user.js","sourceRoot":"","sources":["resync-remote-user.ts"],"names":[],"mappings":";;AAAA,0CAAsC;AACtC,8CAA8C;AAE9C,KAAK,UAAU,IAAI,CAAC,IAAY;IAC/B,MAAM,IAAA,gBAAM,GAAE,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,GAAG,2CAAa,uBAAuB,EAAC,CAAC;IAE9D,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,WAAW,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,WAAW;AACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAEnB,iBAAiB;AACjB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAE9B,aAAa;AACb,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE;IAC3B,MAAM,iDAAiD,CAAC;CACxD;AAED,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;AAE9B,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;IACpB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACrB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/backend/tools/show-signin-history.js b/packages/backend/tools/show-signin-history.js deleted file mode 100644 index daeea84613..0000000000 --- a/packages/backend/tools/show-signin-history.js +++ /dev/null @@ -1,47 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const index_1 = require("@/models/index"); -// node built/tools/show-signin-history username -// => {Success} {Date} {IPAddrsss} -// node built/tools/show-signin-history username user-agent,x-forwarded-for -// with user-agent and x-forwarded-for -// node built/tools/show-signin-history username all -// with full request headers -async function main(username, headers) { - const user = await index_1.Users.findOne({ - host: null, - usernameLower: username.toLowerCase(), - }); - if (user == null) - throw new Error('User not found'); - const history = await index_1.Signins.find({ - userId: user.id - }); - for (const signin of history) { - console.log(`${signin.success ? 'OK' : 'NG'} ${signin.createdAt ? signin.createdAt.toISOString() : 'Unknown'} ${signin.ip}`); - // headers - if (headers != null) { - for (const key of Object.keys(signin.headers)) { - if (headers.includes('all') || headers.includes(key)) { - console.log(` ${key}: ${signin.headers[key]}`); - } - } - } - } -} -// get args -const args = process.argv.slice(2); -let username = args[0]; -let headers; -if (args[1] != null) { - headers = args[1].split(/,/).map(header => header.toLowerCase()); -} -// normalize args -username = username.replace(/^@/, ''); -main(username, headers).then(() => { - process.exit(0); -}).catch(e => { - console.warn(e); - process.exit(1); -}); -//# sourceMappingURL=show-signin-history.js.map \ No newline at end of file diff --git a/packages/backend/tools/show-signin-history.js.map b/packages/backend/tools/show-signin-history.js.map deleted file mode 100644 index b421825bce..0000000000 --- a/packages/backend/tools/show-signin-history.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"show-signin-history.js","sourceRoot":"","sources":["show-signin-history.ts"],"names":[],"mappings":";;AAAA,0CAAgD;AAEhD,gDAAgD;AAChD,mCAAmC;AAEnC,2EAA2E;AAC3E,uCAAuC;AAEvC,oDAAoD;AACpD,6BAA6B;AAE7B,KAAK,UAAU,IAAI,CAAC,QAAgB,EAAE,OAAkB;IACvD,MAAM,IAAI,GAAG,MAAM,aAAK,CAAC,OAAO,CAAC;QAChC,IAAI,EAAE,IAAI;QACV,aAAa,EAAE,QAAQ,CAAC,WAAW,EAAE;KACrC,CAAC,CAAC;IAEH,IAAI,IAAI,IAAI,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,MAAM,eAAO,CAAC,IAAI,CAAC;QAClC,MAAM,EAAE,IAAI,CAAC,EAAE;KACf,CAAC,CAAC;IAEH,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;QAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QAE7H,UAAU;QACV,IAAI,OAAO,IAAI,IAAI,EAAE;YACpB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;gBAC9C,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;oBACrD,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;iBACjD;aACD;SACD;KACD;AACF,CAAC;AAED,WAAW;AACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACvB,IAAI,OAA6B,CAAC;AAElC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE;IACpB,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;CACjE;AAED,iBAAiB;AACjB,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAEtC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/client/src/components/dialog.vue b/packages/client/src/components/dialog.vue index 1b03e65a3d..5d6678531d 100644 --- a/packages/client/src/components/dialog.vue +++ b/packages/client/src/components/dialog.vue @@ -14,7 +14,9 @@
- + + + + + diff --git a/packages/client/src/components/form/input.vue b/packages/client/src/components/form/input.vue index 99267f9231..c990b693f1 100644 --- a/packages/client/src/components/form/input.vue +++ b/packages/client/src/components/form/input.vue @@ -5,6 +5,7 @@
- {{ $ts.save }} + {{ $ts.save }} @@ -114,9 +115,9 @@ export default defineComponent({ const changed = ref(false); const invalid = ref(false); const filled = computed(() => v.value !== '' && v.value != null); - const inputEl = ref(null); - const prefixEl = ref(null); - const suffixEl = ref(null); + const inputEl = ref(); + const prefixEl = ref(); + const suffixEl = ref(); const focus = () => inputEl.value.focus(); const onInput = (ev) => { @@ -208,7 +209,7 @@ export default defineComponent({ .matxzzsk { > .label { font-size: 0.85em; - padding: 0 0 8px 12px; + padding: 0 0 8px 0; user-select: none; &:empty { @@ -217,8 +218,8 @@ export default defineComponent({ } > .caption { - font-size: 0.8em; - padding: 8px 0 0 12px; + font-size: 0.85em; + padding: 8px 0 0 0; color: var(--fgTransparentWeak); &:empty { @@ -242,8 +243,7 @@ export default defineComponent({ font-weight: normal; font-size: 1em; color: var(--fg); - background: var(--panel); - border: solid 0.5px var(--inputBorder); + border: solid 0.5px var(--panel); border-radius: 6px; outline: none; box-shadow: none; @@ -311,5 +311,9 @@ export default defineComponent({ } } } + + > .save { + margin: 8px 0 0 0; + } } diff --git a/packages/client/src/components/form/link.vue b/packages/client/src/components/form/link.vue new file mode 100644 index 0000000000..3eb74425b0 --- /dev/null +++ b/packages/client/src/components/form/link.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/packages/client/src/components/form/pagination.vue b/packages/client/src/components/form/pagination.vue new file mode 100644 index 0000000000..3d3b40a783 --- /dev/null +++ b/packages/client/src/components/form/pagination.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/packages/client/src/components/form/radio.vue b/packages/client/src/components/form/radio.vue index 0f31d8fa0a..f0b8c71376 100644 --- a/packages/client/src/components/form/radio.vue +++ b/packages/client/src/components/form/radio.vue @@ -1,5 +1,6 @@ @@ -118,10 +118,14 @@ export default defineComponent({ transition: inherit; } - > p { - margin: 0; + > .caption { + margin: 8px 0 0 0; color: var(--fgTransparentWeak); - font-size: 90%; + font-size: 0.85em; + + &:empty { + display: none; + } } } diff --git a/packages/client/src/components/form/textarea.vue b/packages/client/src/components/form/textarea.vue index f3a2c394f1..98fd0da94b 100644 --- a/packages/client/src/components/form/textarea.vue +++ b/packages/client/src/components/form/textarea.vue @@ -4,6 +4,7 @@
Roujo