Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a2f06acaa4 | ||
![]() |
8c90cbcbfb | ||
![]() |
a4a47772dc | ||
![]() |
5dde1f4602 | ||
![]() |
9dc0909eeb | ||
![]() |
0ed2592e41 | ||
![]() |
76cff98220 | ||
![]() |
60604b6f51 | ||
![]() |
f410b7aecb | ||
![]() |
1a61f2cee9 | ||
![]() |
78a8293520 | ||
![]() |
03cfb4fc8d | ||
![]() |
144345a359 | ||
![]() |
fd2c01515e | ||
![]() |
219570e08b | ||
![]() |
69df556ff5 |
@@ -1,6 +1,12 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
10.92.2
|
||||
----------
|
||||
* 管理画面で各種ジョブ数を一覧できるように
|
||||
* ジョブキューの動作を修正
|
||||
* notes/children が遅い問題を修正
|
||||
|
||||
10.92.1
|
||||
----------
|
||||
* アンケートの結果をリモートと同期するように
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<img src="https://github.com/syuilo/misskey/blob/develop/assets/ai-orig.png?raw=true" align="right" height="320px"/>
|
||||
<a href="https://ai.misskey.xyz/"><img src="https://github.com/syuilo/misskey/blob/develop/assets/ai-orig.png?raw=true" align="right" height="320px"/></a>
|
||||
|
||||
[](https://misskey.xyz/)
|
||||
================================================================
|
||||
|
@@ -143,7 +143,12 @@ common:
|
||||
i-like-sushi: "Mam radši sushi (než puding)"
|
||||
show-reversi-board-labels: "Zobrazit označení řad a sloupců v Reversi"
|
||||
use-avatar-reversi-stones: "Použít avatar jako figurku v Reversi"
|
||||
disable-animated-mfm: "Vypnout pohyblivé texty v příspěvku"
|
||||
disable-showing-animated-images: "Nepřehrávat animované obrázky"
|
||||
suggest-recent-hashtags: "Navrhovat nedávné hashtagy v rámci psacího pole"
|
||||
always-show-nsfw: "Vždycky ukázat NSFW obsah"
|
||||
always-mark-nsfw: "Označovat všechny příspěvky za delikátní"
|
||||
show-full-acct: "Zaradit hostovací server jako součast přezdívky"
|
||||
show-via: "zobrazit přes"
|
||||
reduce-motion: "Snížit pohyb v rozhraní"
|
||||
this-setting-is-this-device-only: "Pouze pro toto zařízení"
|
||||
@@ -276,22 +281,32 @@ auth/views/form.vue:
|
||||
share-access: "Chcete dovolit aplikaci <i>{name}</i> přístup k vašemu účtu?"
|
||||
permission-ask: "Tato aplikace vyžaduje následující oprávnění:"
|
||||
account-read: "Zobrazit informace účtu"
|
||||
note-write: "Odeslat."
|
||||
following-write: "Sledovat a přestat sledovat"
|
||||
drive-read: "Přečíst váš Disk"
|
||||
notification-read: "Sledovat oznámení."
|
||||
notification-write: "Zpravovat notifikace."
|
||||
cancel: "Zrušit"
|
||||
accept: "Povolit přístup"
|
||||
auth/views/index.vue:
|
||||
loading: "Načítám..."
|
||||
already-authorized: "Tato aplikace byla již autorizována."
|
||||
error: "Taková relace neexistuje."
|
||||
sign-in: "Prosím přihlaste se."
|
||||
common/views/pages/explore.vue:
|
||||
verified-users: "Ověřené účty"
|
||||
popular-users: "Populární uživatelé"
|
||||
recently-updated-users: "Nedávno aktívni uživatelé"
|
||||
recently-registered-users: "Nedávno registrovaní uživatelé"
|
||||
popular-tags: "Populární tagy"
|
||||
federated: "Z fediverse"
|
||||
common/views/components/url-preview.vue:
|
||||
enable-player: "Otevřít v přehrávači"
|
||||
common/views/components/user-list.vue:
|
||||
no-users: "Žádní uživatelé"
|
||||
common/views/components/games/reversi/reversi.vue:
|
||||
matching:
|
||||
waiting-for: "Čeká se na {}"
|
||||
cancel: "Zrušit"
|
||||
common/views/components/games/reversi/reversi.game.vue:
|
||||
surrender: "Vzdát se"
|
||||
@@ -305,14 +320,21 @@ common/views/components/games/reversi/reversi.index.vue:
|
||||
my-games: "Moje hra"
|
||||
all-games: "Všechny hry"
|
||||
enter-username: "Zadejte své uživatelské jméno"
|
||||
game-state:
|
||||
ended: "Ukončené"
|
||||
playing: "Probíhají"
|
||||
common/views/components/games/reversi/reversi.room.vue:
|
||||
settings-of-the-game: "Nastavení hry"
|
||||
choose-map: "Vybrat mapu"
|
||||
random: "Náhodně"
|
||||
black-or-white: "Černé/bílé"
|
||||
black-is: "Černá je {}"
|
||||
rules: "Pravidla"
|
||||
looped-map: "Zacyklená mapa"
|
||||
settings-of-the-bot: "Nastavení Botu"
|
||||
this-game-is-started-soon: "Hra začne za pár vteřin"
|
||||
waiting-for-other: "Čeká se na protivníka"
|
||||
waiting-for-me: "Čeká se na Vás"
|
||||
waiting-for-both: "Připravuji"
|
||||
cancel: "Zrušit"
|
||||
ready: "Připraveno"
|
||||
@@ -325,7 +347,22 @@ common/views/components/connect-failed.troubleshooter.vue:
|
||||
checking-network: "Prověřit síťové připojení"
|
||||
internet: "Připojení k internetu"
|
||||
checking-internet: "Ověřuji připojení k internetu."
|
||||
server: "Připojení k serveru"
|
||||
no-network-desc: "Ujistěte se že jste připojeni k Internetu."
|
||||
no-internet: "Nejste připojeni k internetu"
|
||||
no-internet-desc: "Jste připojen k síti, ale zdá se že stále chybí připojení k Internetu. Prosím zkontrolujte Vaše připojení k Internetu."
|
||||
common/views/components/media-banner.vue:
|
||||
click-to-show: "Klikněte pro zobrazení"
|
||||
common/views/components/theme.vue:
|
||||
light-theme: "Šablona pro použití ve světlém vzhledu"
|
||||
dark-theme: "Šablona pro použití v tmavém vzhledu"
|
||||
light-themes: "Světlý vzhled"
|
||||
dark-themes: "Tmavý vzhled"
|
||||
install-a-theme: "Nainstalovat šablonu"
|
||||
theme-code: "Kód šablony"
|
||||
install: "Nainstalovat"
|
||||
installed: "\"{}\" byl nainstalován"
|
||||
create-a-theme: "Vytvořit motiv"
|
||||
base-theme: "Základní vzhled"
|
||||
find-more-theme: "Najít další vzhledy"
|
||||
theme-name: "Jméno vzhledu"
|
||||
@@ -359,6 +396,7 @@ common/views/components/messaging-room.vue:
|
||||
only-one-file-attached: "Jenom JEDEN soubor může být přiložen ke zprávě."
|
||||
common/views/components/messaging-room.form.vue:
|
||||
send: "Odeslat"
|
||||
attach-from-local: "Přiložit soubory z Vašeho zařízení"
|
||||
only-one-file-attached: "Jenom JEDEN soubor může být přiložen ke zprávě."
|
||||
common/views/components/messaging-room.message.vue:
|
||||
is-read: "Přečtené"
|
||||
@@ -371,16 +409,41 @@ common/views/components/nav.vue:
|
||||
donors: "Dárci"
|
||||
repository: "Úložiště"
|
||||
develop: "Vývojáři"
|
||||
feedback: "Zpětná vazba"
|
||||
common/views/components/note-menu.vue:
|
||||
mention: "Zmínění"
|
||||
copy-content: "Zkopírovat obsah"
|
||||
copy-link: "Zkopírovat odkaz"
|
||||
favorite: "Přidat do oblíbených"
|
||||
unfavorite: "Odebrat z oblízených"
|
||||
watch: "Sledovat"
|
||||
unwatch: "Přestat sledovat"
|
||||
delete: "Odstranit"
|
||||
delete-confirm: "Opravdu chcete smazat tento příspěvek?"
|
||||
remote: "Ukázat originální poznámku"
|
||||
common/views/components/user-menu.vue:
|
||||
mention: "Zmínění"
|
||||
mute: "Umlčet"
|
||||
unmute: "Zrušit umlčení"
|
||||
block: "Blokován"
|
||||
unblock: "Odblokovat"
|
||||
push-to-list: "Přidat do seznamu"
|
||||
select-list: "Vyberte seznam"
|
||||
report-abuse-reported: "Problém byl nahlášen administrátorovi. Děkujeme za Vaší kooperaci."
|
||||
common/views/components/poll.vue:
|
||||
vote-count: "{} hlasů"
|
||||
vote: "Hlasovat"
|
||||
show-result: "Podívat se na výsledky"
|
||||
voted: "Už jste hlasovaly"
|
||||
remaining-days: "zbývá {d} dnů, {h} hodin"
|
||||
remaining-hours: "zbývá {h} hodin, a {m} minut"
|
||||
remaining-minutes: "zbývá {m} minut, a {s} sekund"
|
||||
remaining-seconds: "zbývá {s} sekund"
|
||||
common/views/components/poll-editor.vue:
|
||||
no-only-one-choice: "Musíte vybrat alespoň dvě možnosti"
|
||||
day: "Ne"
|
||||
common/views/components/emoji-picker.vue:
|
||||
custom-emoji: "Emoji"
|
||||
people: "Lidé"
|
||||
animals-and-nature: "Zvířata a příroda"
|
||||
food-and-drink: "Jídlo a pití"
|
||||
@@ -433,20 +496,53 @@ common/views/components/notification-settings.vue:
|
||||
mark-as-read-all-notifications: "Označit všechna oznámení za přečtená"
|
||||
mark-as-read-all-unread-notes: "Označit všechny příspěvky za přečtené"
|
||||
mark-as-read-all-talk-messages: "Označit všechny zprávy za přečtené"
|
||||
common/views/components/integration-settings.vue:
|
||||
connect: "Připojit"
|
||||
disconnect: "Odpojit"
|
||||
common/views/components/github-setting.vue:
|
||||
description: "Jakmile spojíte Váš GitHub účet s Vaším Misskey účtem, uvidíte informace o Vašem GitHub účtu na Vašem profilu a budete se moci přihlásit skrze GitHub."
|
||||
connected-to: "Je připojen k tomuto GitHub účtu"
|
||||
detail: "Více…"
|
||||
reconnect: "Znovu připojit"
|
||||
connect: "Připojit Váš GitHub účet"
|
||||
disconnect: "Odpojit"
|
||||
common/views/components/discord-setting.vue:
|
||||
description: "Jakmile spojíte Váš Discord účet s Vaším Misskey účtem, uvidíte informace o Vašem Discord účtu na Vašem profilu a budete se moci přihlásit skrze Discord."
|
||||
connected-to: "Je připojen k tomuto Discord účtu"
|
||||
detail: "Více…"
|
||||
reconnect: "Znovu připojit"
|
||||
connect: "Připojit Váš Discord účet"
|
||||
disconnect: "Odpojit"
|
||||
common/views/components/uploader.vue:
|
||||
waiting: "Čekáme"
|
||||
common/views/components/visibility-chooser.vue:
|
||||
public: "Veřejné"
|
||||
home: "Domů"
|
||||
specified-desc: "Poslat pouze zmíněným uživatelům"
|
||||
local-public: "Veřejná (pouze místní)"
|
||||
local-home: "Domovská (pouze místní)"
|
||||
local-followers: "Pro sledující (pouze místní)"
|
||||
common/views/components/trends.vue:
|
||||
count: "{} zmíněných uživatelů"
|
||||
empty: "Žádný trend"
|
||||
common/views/components/language-settings.vue:
|
||||
title: "Zobrazit jazyky"
|
||||
pick-language: "Zvolte jazyk"
|
||||
recommended: "Doporučené"
|
||||
info: "Pro aktivování změn musíte znovu načíst stránky."
|
||||
common/views/components/profile-editor.vue:
|
||||
title: "Profil"
|
||||
name: "Jméno"
|
||||
account: "Účet"
|
||||
location: "Lokace"
|
||||
description: "O mně"
|
||||
you-can-include-hashtags: "V popisku o Vás můžete použít i hastagy."
|
||||
language: "Jazyk"
|
||||
birthday: "Datum narození"
|
||||
avatar: "Avatar"
|
||||
banner: "Baner"
|
||||
is-cat: "Tento účet je kočka"
|
||||
is-bot: "Tento účet je Bot"
|
||||
advanced: "Ostatní"
|
||||
privacy: "Osobní údaje"
|
||||
save: "Uložit"
|
||||
@@ -474,6 +570,7 @@ common/views/components/user-list-editor.vue:
|
||||
delete-are-you-sure: "Smazat seznam \"$1\"?"
|
||||
deleted: "Smazáno"
|
||||
common/views/widgets/broadcast.vue:
|
||||
fetching: "Načítám"
|
||||
next: "Další"
|
||||
common/views/widgets/calendar.vue:
|
||||
year: "Rok {}"
|
||||
@@ -486,10 +583,12 @@ common/views/widgets/photo-stream.vue:
|
||||
no-photos: "Žádné obrázky"
|
||||
common/views/widgets/posts-monitor.vue:
|
||||
title: "Grafy příspěvků"
|
||||
toggle: "Přepnout zobrazení"
|
||||
common/views/widgets/hashtags.vue:
|
||||
title: "Hashtagy"
|
||||
common/views/widgets/server.vue:
|
||||
title: "Informace o serveru"
|
||||
toggle: "Přepnout zobrazení"
|
||||
common/views/widgets/memo.vue:
|
||||
title: "Poznámky"
|
||||
memo: "Pište sem!"
|
||||
@@ -498,6 +597,11 @@ common/views/widgets/slideshow.vue:
|
||||
no-image: "V této složce nebyly nalezeny žádné fotky."
|
||||
desktop:
|
||||
banner: "Baner"
|
||||
avatar-crop-title: "Vyberte část, která se zobrazí jako avatar"
|
||||
avatar: "Avatar"
|
||||
uploading-avatar: "Nahrál nový avatar"
|
||||
avatar-updated: "Vaše avatar byl aktualizován"
|
||||
invalid-filetype: "Tento formát souboru není podporován"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Černá ... Celkem"
|
||||
notes: "Modrá ... Poznámky"
|
||||
@@ -505,6 +609,7 @@ desktop/views/components/activity.chart.vue:
|
||||
renotes: "Zelená ... Renoty"
|
||||
desktop/views/components/activity.vue:
|
||||
title: "Aktivita"
|
||||
toggle: "Přepnout zobrazení"
|
||||
desktop/views/components/calendar.vue:
|
||||
title: "{month}. {year}"
|
||||
prev: "Předchozí měsíc"
|
||||
@@ -522,6 +627,8 @@ desktop/views/components/choose-folder-from-drive-window.vue:
|
||||
desktop/views/components/crop-window.vue:
|
||||
cancel: "Zrušit"
|
||||
ok: "OK"
|
||||
desktop/views/components/drive-window.vue:
|
||||
used: "využito"
|
||||
desktop/views/components/drive.file.vue:
|
||||
avatar: "Avatar"
|
||||
banner: "Baner"
|
||||
@@ -553,13 +660,41 @@ desktop/views/components/drive.vue:
|
||||
empty-folder: "Tato složka je prázdná"
|
||||
unable-to-process: "Operace nemohla být dokončena."
|
||||
unhandled-error: "Neznámá chyba"
|
||||
url-upload: "Nahrát z URL adresy"
|
||||
url-of-file: "URL adresa souboru, který chcete nahrát"
|
||||
may-take-time: "Může trvat nějakou dobu, dokud nebude dokončeno nahrávání."
|
||||
create-folder: "Vytvořit složku"
|
||||
folder-name: "Název složky"
|
||||
contextmenu:
|
||||
create-folder: "Vytvořit složku"
|
||||
upload: "Nahrát soubor"
|
||||
url-upload: "Nahrát z URL"
|
||||
desktop/views/components/media-video.vue:
|
||||
click-to-show: "Klikněte pro zobrazení"
|
||||
desktop/views/components/game-window.vue:
|
||||
game: "Reversi"
|
||||
desktop/views/components/home.vue:
|
||||
done: "Hotovo"
|
||||
add: "Přidat"
|
||||
desktop/views/input-dialog.vue:
|
||||
cancel: "Zrušit"
|
||||
ok: "OK"
|
||||
desktop/views/components/messaging-room-window.vue:
|
||||
title: "Zprávy:"
|
||||
desktop/views/components/messaging-window.vue:
|
||||
title: "Zprávy"
|
||||
desktop/views/components/note-detail.vue:
|
||||
private: "Tento příspěvek je soukromý"
|
||||
deleted: "Tento příspěvek byl odstraněn"
|
||||
renote: "Renotovat"
|
||||
add-reaction: "Přidat reakci"
|
||||
undo-reaction: "Odebrat reakci"
|
||||
desktop/views/components/note.vue:
|
||||
reply: "Odpovědět"
|
||||
renote: "Renote"
|
||||
add-reaction: "Přidat reakci"
|
||||
undo-reaction: "Odebrat reakci"
|
||||
private: "Tento příspěvek je soukromý"
|
||||
deleted: "Tento příspěvek byl odstraněn"
|
||||
desktop/views/components/notes.vue:
|
||||
error: "Načítání selhalo."
|
||||
@@ -570,22 +705,27 @@ desktop/views/components/post-form.vue:
|
||||
hide-contents: "Schovat obsah"
|
||||
reply-placeholder: "Odpovědět na tento příspěvěk"
|
||||
quote-placeholder: "Citovat tento příspěvek"
|
||||
submit: "Příspěvek"
|
||||
reply: "Odpovědět"
|
||||
renote: "Renotovat"
|
||||
posted: "Odesláno!"
|
||||
replied: "Odpověděno!"
|
||||
reposted: "Renotováno!"
|
||||
note-failed: "Nepodařilo se přidat příspěvek"
|
||||
renote-failed: "Renotování neuspělo"
|
||||
insert-a-kao: "v('ω')v"
|
||||
create-poll: "Vytvořit anketu"
|
||||
text-remain: "{0} znaků zbývá"
|
||||
recent-tags: "Nejnovější"
|
||||
visibility: "Viditelnost"
|
||||
geolocation-alert: "Vaše zařízení nepodporuje lokační službu"
|
||||
error: "Chyba"
|
||||
enter-username: "Zadejte své uživatelské jméno..."
|
||||
desktop/views/components/post-form-window.vue:
|
||||
note: "Nový příspěvek"
|
||||
reply: "Odpovědět"
|
||||
desktop/views/components/progress-dialog.vue:
|
||||
waiting: "Čekáme"
|
||||
desktop/views/components/renote-form.vue:
|
||||
quote: "Citovat..."
|
||||
cancel: "Zrušit"
|
||||
@@ -599,14 +739,23 @@ desktop/views/components/renote-form-window.vue:
|
||||
desktop/views/components/settings.2fa.vue:
|
||||
detail: "Více…"
|
||||
url: "https://www.google.cz/landing/2step/"
|
||||
common/views/components/media-image.vue:
|
||||
click-to-show: "Klikněte pro zobrazení"
|
||||
common/views/components/api-settings.vue:
|
||||
token: "Token:"
|
||||
enter-password: "Prosím zadejte heslo"
|
||||
console:
|
||||
title: "API konzole"
|
||||
endpoint: "Endpoint"
|
||||
parameter: "Parametry"
|
||||
send: "Odeslat"
|
||||
sending: "Odesílám"
|
||||
response: "Výsledek"
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "Žádné připojené aplikace"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "Velikost úložiště"
|
||||
in-use: "využito"
|
||||
stats: "Statistiky"
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "Umlčet/blokovat"
|
||||
@@ -634,21 +783,55 @@ desktop/views/components/settings.tags.vue:
|
||||
desktop/views/components/taskmanager.vue:
|
||||
title: "Správce úloh"
|
||||
desktop/views/components/timeline.vue:
|
||||
home: "Domů"
|
||||
local: "Lokální"
|
||||
global: "Globální"
|
||||
mentions: "Zmínění"
|
||||
messages: "Zprávy"
|
||||
list: "Seznamy"
|
||||
hashtag: "Hashtag"
|
||||
add-list: "Přidat do seznamu"
|
||||
list-name: "Název seznamu"
|
||||
desktop/views/components/ui.header.vue:
|
||||
welcome-back: "Vítejte zpátky,"
|
||||
adjective: "Pán"
|
||||
desktop/views/components/ui.header.account.vue:
|
||||
profile: "Váš profil"
|
||||
lists: "Seznamy"
|
||||
admin: "Administrace"
|
||||
desktop/views/components/ui.header.nav.vue:
|
||||
game: "Hry"
|
||||
desktop/views/components/ui.header.notifications.vue:
|
||||
title: "Oznámení"
|
||||
desktop/views/components/ui.header.post.vue:
|
||||
post: "Nový příspěvek"
|
||||
desktop/views/components/ui.header.search.vue:
|
||||
placeholder: "Vyhledávání"
|
||||
desktop/views/components/received-follow-requests-window.vue:
|
||||
accept: "Přijmout"
|
||||
reject: "Odmítnout"
|
||||
desktop/views/components/user-lists-window.vue:
|
||||
title: "Seznamy uživatelů"
|
||||
create-list: "Vytvořit seznam"
|
||||
list-name: "Název seznamu"
|
||||
desktop/views/components/user-preview.vue:
|
||||
notes: "Příspěvky"
|
||||
desktop/views/components/users-list.vue:
|
||||
all: "Všechny"
|
||||
iknow: "Znáte"
|
||||
fetching: "Načítám…"
|
||||
desktop/views/components/window.vue:
|
||||
close: "Zavřít"
|
||||
admin/views/index.vue:
|
||||
instance: "Instance"
|
||||
emoji: "Emoji"
|
||||
moderators: "Moderátoři"
|
||||
users: "Uživatelé"
|
||||
federation: "Z fediversu"
|
||||
announcements: "Oznámení"
|
||||
hashtags: "Hashtagy"
|
||||
queue: "Fronta úloh"
|
||||
logs: "Logy"
|
||||
back-to-misskey: "Zpět na Misskey"
|
||||
admin/views/dashboard.vue:
|
||||
accounts: "Účty"
|
||||
@@ -699,9 +882,19 @@ admin/views/instance.vue:
|
||||
saved: "Uloženo"
|
||||
user-recommendation-config: "Doporučení uživatelé"
|
||||
email: "Emailová adresa"
|
||||
smtp-port: "SMTP Port"
|
||||
smtp-auth: "Provést SMTP autentikaci"
|
||||
smtp-user: "SMTP uživatel"
|
||||
smtp-pass: "SMTP heslo"
|
||||
serviceworker-config: "ServiceWorker"
|
||||
enable-serviceworker: "Povolit ServiceWorker"
|
||||
vapid-publickey: "VAPID veřejný klíč"
|
||||
vapid-privatekey: "VAPID osobní klíč"
|
||||
admin/views/charts.vue:
|
||||
title: "Graf"
|
||||
per-day: "za den"
|
||||
per-hour: "za hodinu"
|
||||
federation: "Federace"
|
||||
notes: "Příspěvky"
|
||||
users: "Uživatelé"
|
||||
drive: "Disk"
|
||||
@@ -709,11 +902,20 @@ admin/views/charts.vue:
|
||||
charts:
|
||||
federation-instances: "Počet instancí: zvýšení/snížení"
|
||||
federation-instances-total: "Celkový počet instancí"
|
||||
notes-total: "Celkem příspěvků"
|
||||
users-total: "Celkem uživatelů"
|
||||
active-users: "Aktivní uživatelé"
|
||||
network-requests: "Požadavek"
|
||||
network-time: "Doba odezvy"
|
||||
network-usage: "Síťový provoz"
|
||||
admin/views/drive.vue:
|
||||
operation: "Operace"
|
||||
fileid-or-url: "ID nebo URL souboru"
|
||||
file-not-found: "Soubor nebyl nalezen"
|
||||
sort:
|
||||
title: "Seřadit"
|
||||
createdAtAsc: "Věk - od nejstaršího"
|
||||
createdAtDesc: "Věk - od nejmladšího"
|
||||
sizeAsc: "Velikost - od nejmenších"
|
||||
sizeDesc: "Velikost – od největších"
|
||||
origin:
|
||||
@@ -730,8 +932,17 @@ admin/views/users.vue:
|
||||
reset-password: "Resetovat heslo"
|
||||
reset-password-confirm: "Opravdu chcete resetovat Vaše heslo?"
|
||||
password-updated: "Heslo je nyní \"{password}\""
|
||||
verify: "Ověřit účet"
|
||||
verify-confirm: "Chcete aby toto byl ověřený účet?"
|
||||
verified: "Účet se nyní ověřuje"
|
||||
unverify: "Zrušit ověření účtu"
|
||||
unverify-confirm: "Opravdu chcete zrušit designaci \"ověřený účet\"?"
|
||||
unverified: "Ruší se potvrzení účtu"
|
||||
update-remote-user: "Aktualizovat informace o vzdáleném účtu"
|
||||
users:
|
||||
title: "Uživatel"
|
||||
state:
|
||||
all: "Všechny"
|
||||
moderator: "Moderátor"
|
||||
adminOrModerator: "Admin/Moderátor"
|
||||
verified: "Ověřený účet"
|
||||
@@ -784,61 +995,181 @@ admin/views/federation.vue:
|
||||
status: "Status"
|
||||
latest-request-received-at: "Poslední požadavek přijat"
|
||||
block: "Blokován"
|
||||
instances: "Instance"
|
||||
states:
|
||||
all: "Všechny"
|
||||
blocked: "Blokován"
|
||||
not-responding: "Bez odpovědi"
|
||||
marked-as-closed: "Označeno jako uzavřené"
|
||||
charts: "Graf"
|
||||
chart-srcs:
|
||||
requests: "Požadavek"
|
||||
users-total: "Celkem uživatelů"
|
||||
notes-total: "Celkem příspěvků"
|
||||
chart-spans:
|
||||
hour: "za hodinu"
|
||||
day: "za den"
|
||||
desktop/views/pages/welcome.vue:
|
||||
about: "O Misskey"
|
||||
timeline: "Časová osa"
|
||||
announcements: "Oznámení"
|
||||
photos: "Nedávné obrázky"
|
||||
powered-by-misskey: "Běží na <b>Misskey</b>."
|
||||
info: "Informace"
|
||||
desktop/views/pages/drive.vue:
|
||||
title: "Misskey Disk"
|
||||
desktop/views/pages/note.vue:
|
||||
prev: "Předchozí příspěvěk"
|
||||
next: "Následující příspěvek"
|
||||
desktop/views/pages/selectdrive.vue:
|
||||
title: "Vyberte soubor(y)"
|
||||
ok: "OK"
|
||||
cancel: "Zrušit"
|
||||
upload: "Nahrajte soubory z vašeho zařízení"
|
||||
desktop/views/pages/search.vue:
|
||||
not-available: "Vyhledávání je vypnuté pro tuto instanci."
|
||||
not-found: "Pro '{q}' nebyly nalezeny žádné příspěvky."
|
||||
desktop/views/pages/share.vue:
|
||||
share-with: "Sdílet na {name}"
|
||||
desktop/views/pages/tag.vue:
|
||||
no-posts-found: "Nebyly nalezeny žádné příspěvky s \"{q}\"."
|
||||
desktop/views/pages/user-list.users.vue:
|
||||
users: "Uživatel"
|
||||
add-user: "Přidat uživatele"
|
||||
username: "Přezdívka"
|
||||
desktop/views/pages/user/user.followers-you-know.vue:
|
||||
loading: "Načítám..."
|
||||
desktop/views/pages/user/user.friends.vue:
|
||||
title: "Častá zmínění"
|
||||
loading: "Načítám..."
|
||||
no-users: "Žádná častá zmínění"
|
||||
desktop/views/pages/user/user.photos.vue:
|
||||
title: "Fotky"
|
||||
loading: "Načítám..."
|
||||
no-photos: "Žádné obrázky"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "Poznámky"
|
||||
month: "Po"
|
||||
day: "Ne"
|
||||
desktop/views/widgets/messaging.vue:
|
||||
title: "Zprávy"
|
||||
desktop/views/widgets/notifications.vue:
|
||||
title: "Oznámení"
|
||||
desktop/views/widgets/polls.vue:
|
||||
title: "Ankety"
|
||||
desktop/views/widgets/users.vue:
|
||||
title: "Doporučení uživatelé"
|
||||
mobile/views/components/drive.vue:
|
||||
used: "využito"
|
||||
file-count: "Soubor(ů)"
|
||||
folder-is-empty: "Tato složka je prázdná"
|
||||
deletion-alert: "Omlouváme se, ale mazání složek ještě nebylo implementováno."
|
||||
folder-name: "Název složky"
|
||||
url-prompt: "URL adresa souboru, který chcete nahrát"
|
||||
uploading: "Byl zahájen upload. Může chvilku trvat než bude dokončen."
|
||||
mobile/views/components/drive-file-chooser.vue:
|
||||
select-file: "Vybrat soubory"
|
||||
mobile/views/components/drive-folder-chooser.vue:
|
||||
select-folder: "Vyberte složku"
|
||||
mobile/views/components/drive.file-detail.vue:
|
||||
download: "Stáhnout"
|
||||
rename: "Přejmenovat"
|
||||
move: "Přesunout"
|
||||
hash: "Hash (md5)"
|
||||
exif: "EXIF"
|
||||
mobile/views/components/media-video.vue:
|
||||
click-to-show: "Klikněte pro zobrazení"
|
||||
common/views/components/follow-button.vue:
|
||||
follow-processing: "Zpracovávám"
|
||||
mobile/views/components/note.vue:
|
||||
private: "Tento příspěvek je soukromý"
|
||||
deleted: "Tento příspěvek byl odstraněn"
|
||||
location: "Lokace"
|
||||
mobile/views/components/note-detail.vue:
|
||||
reply: "Odpovědět"
|
||||
reaction: "Reakce"
|
||||
private: "Tento příspěvek je soukromý"
|
||||
deleted: "Tento příspěvek byl odstraněn"
|
||||
location: "Lokace"
|
||||
mobile/views/components/note-preview.vue:
|
||||
admin: "admin"
|
||||
bot: "bot"
|
||||
cat: "kočka"
|
||||
mobile/views/components/note-sub.vue:
|
||||
admin: "admin"
|
||||
bot: "bot"
|
||||
cat: "kočka"
|
||||
mobile/views/components/post-form.vue:
|
||||
add-visible-user: "Přidat uživatele"
|
||||
submit: "Příspěvek"
|
||||
reply: "Odpovědět"
|
||||
renote: "Renotovat"
|
||||
reply-placeholder: "Odpovědět na tento příspěvěk"
|
||||
location-alert: "Vaše zařízení nepodporuje lokační službu"
|
||||
error: "Chyba"
|
||||
username-prompt: "Zadejte uživatelské jméno"
|
||||
mobile/views/components/sub-note-content.vue:
|
||||
private: "Tento příspěvek je soukromý"
|
||||
deleted: "Tento příspěvek byl odstraněn"
|
||||
poll: "Ankety"
|
||||
mobile/views/components/ui.header.vue:
|
||||
welcome-back: "Vítejte zpátky,"
|
||||
adjective: "Pán"
|
||||
mobile/views/components/ui.nav.vue:
|
||||
timeline: "Časová osa"
|
||||
notifications: "Oznámení"
|
||||
search: "Vyhledávání"
|
||||
user-lists: "Seznamy"
|
||||
widgets: "Widgety"
|
||||
game: "Hry"
|
||||
admin: "Administrace"
|
||||
about: "O Misskey"
|
||||
mobile/views/pages/user-lists.vue:
|
||||
title: "Seznamy"
|
||||
mobile/views/pages/signup.vue:
|
||||
lets-start: "Váš účet je připraven! 📦"
|
||||
mobile/views/pages/home.vue:
|
||||
home: "Domů"
|
||||
local: "Lokální"
|
||||
global: "Globální"
|
||||
mentions: "Zmínění"
|
||||
messages: "Zprávy"
|
||||
mobile/views/pages/tag.vue:
|
||||
no-posts-found: "Nebyly nalezeny žádné příspěvky s \"{q}\"."
|
||||
mobile/views/pages/widgets.vue:
|
||||
add-widget: "Přidat"
|
||||
customization-tips: "Tipy pro přizpůsobení"
|
||||
mobile/views/pages/widgets/activity.vue:
|
||||
activity: "Aktivita"
|
||||
mobile/views/pages/share.vue:
|
||||
share-with: "Sdílet na {name}"
|
||||
mobile/views/pages/received-follow-requests.vue:
|
||||
accept: "Přijmout"
|
||||
reject: "Odmítnout"
|
||||
mobile/views/pages/note.vue:
|
||||
prev: "Předchozí příspěvěk"
|
||||
next: "Následující příspěvek"
|
||||
mobile/views/pages/games/reversi.vue:
|
||||
reversi: "Reversi"
|
||||
mobile/views/pages/search.vue:
|
||||
not-found: "Pro '{q}' nebyly nalezeny žádné příspěvky."
|
||||
mobile/views/pages/selectdrive.vue:
|
||||
select-file: "Vybrat soubory"
|
||||
mobile/views/pages/user/home.vue:
|
||||
activity: "Aktivita"
|
||||
frequently-replied-users: "Častá zmínění"
|
||||
mobile/views/pages/user/home.photos.vue:
|
||||
no-photos: "Žádné obrázky"
|
||||
deck:
|
||||
widgets: "Widgety"
|
||||
home: "Domů"
|
||||
local: "Lokální"
|
||||
hashtag: "Hashtagy"
|
||||
global: "Globální"
|
||||
mentions: "Zmínění"
|
||||
notifications: "Oznámení"
|
||||
list: "Seznamy"
|
||||
select-list: "Vyberte seznam"
|
||||
swap-left: "Posunout doleva"
|
||||
swap-right: "Posunout doprava"
|
||||
rename: "Přejmenovat"
|
||||
@@ -848,7 +1179,9 @@ dev/views/new-app.vue:
|
||||
app-name-desc: "Jméno vaší aplikace"
|
||||
app-desc: "Stručný popis nebo představení vaší aplikace."
|
||||
account-read: "Zobrazit informace účtu"
|
||||
note-write: "Odeslat."
|
||||
reaction-write: "Přidat nebo odebrat reakce."
|
||||
following-write: "Sledovat a přestat sledovat"
|
||||
drive-read: "Přečíst váš Disk"
|
||||
notification-read: "Sledovat oznámení."
|
||||
notification-write: "Zpravovat notifikace."
|
||||
|
@@ -223,8 +223,8 @@ common:
|
||||
search: "Search"
|
||||
delete: "Delete"
|
||||
loading: "Loading"
|
||||
ok: "It's OK"
|
||||
cancel: "Quit"
|
||||
ok: "Confirm"
|
||||
cancel: "Exit"
|
||||
update-available-title: "Update available"
|
||||
update-available: "A new version of Misskey is now available({newer}, the current version is {current}). Reload the page to apply updates."
|
||||
my-token-regenerated: "Your token has been regenerated, so you will be signed out."
|
||||
@@ -539,7 +539,7 @@ common/views/components/signin.vue:
|
||||
signin-with-twitter: "Log in with Twitter"
|
||||
signin-with-github: "Sign in with GitHub"
|
||||
signin-with-discord: "Sign in with Discord"
|
||||
login-failed: "Log in failed. Make sure you have entered your correct username and password."
|
||||
login-failed: "Logging in has failed. Make sure you have entered the correct username and password."
|
||||
common/views/components/signup.vue:
|
||||
invitation-code: "Invitation code"
|
||||
invitation-info: "If you do not have an invitation code, please contact an <a href=\"{}\">administrator</a>."
|
||||
@@ -1384,7 +1384,7 @@ desktop/views/pages/user/user.timeline.vue:
|
||||
with-media: "Media"
|
||||
my-posts: "My posts"
|
||||
desktop/views/widgets/messaging.vue:
|
||||
title: "Message"
|
||||
title: "Messaging"
|
||||
desktop/views/widgets/notifications.vue:
|
||||
title: "Notifications"
|
||||
desktop/views/widgets/polls.vue:
|
||||
|
@@ -26,6 +26,7 @@ common:
|
||||
dark-mode: "Tryb ciemny"
|
||||
signin: "Zaloguj się"
|
||||
signup: "Rejestracja"
|
||||
signout: "Wyloguj się"
|
||||
got-it: "Rozumiem!"
|
||||
customization-tips:
|
||||
title: "Wskazówki o dostosowywaniu"
|
||||
@@ -120,6 +121,7 @@ common:
|
||||
other: "Inne"
|
||||
appearance: "Wygląd"
|
||||
behavior: "Zachowanie"
|
||||
note-visibility: "Widoczność wpisów"
|
||||
timeline: "Oś czasu"
|
||||
search: "Szukaj"
|
||||
delete: "Usuń"
|
||||
|
@@ -1 +1,88 @@
|
||||
---
|
||||
meta:
|
||||
lang: "中文(繁体)"
|
||||
common:
|
||||
intro:
|
||||
title: "什麽是 Misskey 呢?"
|
||||
rich-contents: "發佈"
|
||||
reaction: "回應"
|
||||
drive: "雲端硬碟"
|
||||
adblock:
|
||||
detected: "請禁用廣告封鎖器"
|
||||
close: "關閉"
|
||||
enter-password: "請輸入密碼"
|
||||
2fa: "雙重身份驗證"
|
||||
dark-mode: "夜間模式"
|
||||
signup: "註冊"
|
||||
signout: "登出"
|
||||
notification:
|
||||
reversi-invited: "您已被邀請加入壹場遊戲"
|
||||
reversi-invited-by: "來自{}的邀請"
|
||||
notified-by: "來自{}的邀請"
|
||||
time:
|
||||
future: "未來"
|
||||
just_now: "剛剛"
|
||||
drive: "雲端硬碟"
|
||||
weekday:
|
||||
sunday: "週日"
|
||||
monday: "週一"
|
||||
tuesday: "週二"
|
||||
wednesday: "週三"
|
||||
thursday: "週四"
|
||||
friday: "週五"
|
||||
saturday: "週六"
|
||||
reactions:
|
||||
like: "贊"
|
||||
love: "喜歡"
|
||||
congrats: "恭喜"
|
||||
_settings:
|
||||
password: "密碼"
|
||||
font-size: "字體大小"
|
||||
font-size-x-small: "小"
|
||||
font-size-small: "較小"
|
||||
deck-column-width-wide: "寬"
|
||||
timeline: "時間軸"
|
||||
common/views/components/connect-failed.troubleshooter.vue:
|
||||
flush: "清除快取"
|
||||
common/views/components/theme.vue:
|
||||
light-themes: "淺色主題"
|
||||
dark-themes: "深色主題"
|
||||
install-a-theme: "安裝主題"
|
||||
save-created-theme: "保存主題"
|
||||
common/views/components/signin.vue:
|
||||
signin-with-twitter: "用 Twitter 帳號登入"
|
||||
signin-with-github: "用 GitHub 帳號登入"
|
||||
signin-with-discord: "用 Discord 帳號登入"
|
||||
login-failed: "登錄失敗。 請檢查用戶名和密碼。"
|
||||
common/views/components/signup.vue:
|
||||
invitation-code: "邀請碼"
|
||||
username: "用戶名"
|
||||
available: "可用"
|
||||
too-long: "請不要超過20個字元"
|
||||
password: "密碼"
|
||||
password-placeholder: "建議至少8個字元"
|
||||
common/views/components/stream-indicator.vue:
|
||||
connecting: "正在連線"
|
||||
reconnecting: "正在重新連線"
|
||||
connected: "已建立連線"
|
||||
common/views/components/integration-settings.vue:
|
||||
disconnect: "中斷連線"
|
||||
common/views/components/github-setting.vue:
|
||||
reconnect: "重新連線"
|
||||
disconnect: "中斷連線"
|
||||
common/views/components/discord-setting.vue:
|
||||
reconnect: "重新連線"
|
||||
disconnect: "中斷連線"
|
||||
common/views/components/language-settings.vue:
|
||||
recommended: "推薦"
|
||||
auto: "自動"
|
||||
specify-language: "指定語言"
|
||||
common/views/components/profile-editor.vue:
|
||||
title: "個人資料"
|
||||
name: "名稱"
|
||||
birthday: "生日:"
|
||||
privacy: "隱私"
|
||||
admin/views/dashboard.vue:
|
||||
drive: "雲端硬碟"
|
||||
admin/views/charts.vue:
|
||||
drive: "雲端硬碟"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "10.92.1",
|
||||
"version": "10.92.2",
|
||||
"codename": "nighthike",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -85,11 +85,10 @@ export default Vue.extend({
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.nqjzuvev
|
||||
white-space nowrap
|
||||
overflow auto
|
||||
padding 8px
|
||||
background #000
|
||||
color #fff
|
||||
font-size 14px
|
||||
|
||||
> code
|
||||
display block
|
||||
|
@@ -2,6 +2,34 @@
|
||||
<div>
|
||||
<ui-card>
|
||||
<template #title>{{ $t('operation') }}</template>
|
||||
<section>
|
||||
<header>Deliver</header>
|
||||
<ui-horizon-group inputs v-if="stats">
|
||||
<ui-input :value="stats.deliver.waiting | number" type="text" readonly>
|
||||
<span>Waiting</span>
|
||||
</ui-input>
|
||||
<ui-input :value="stats.deliver.delayed | number" type="text" readonly>
|
||||
<span>Delayed</span>
|
||||
</ui-input>
|
||||
<ui-input :value="stats.deliver.active | number" type="text" readonly>
|
||||
<span>Active</span>
|
||||
</ui-input>
|
||||
</ui-horizon-group>
|
||||
</section>
|
||||
<section>
|
||||
<header>Inbox</header>
|
||||
<ui-horizon-group inputs v-if="stats">
|
||||
<ui-input :value="stats.inbox.waiting | number" type="text" readonly>
|
||||
<span>Waiting</span>
|
||||
</ui-input>
|
||||
<ui-input :value="stats.inbox.delayed | number" type="text" readonly>
|
||||
<span>Delayed</span>
|
||||
</ui-input>
|
||||
<ui-input :value="stats.inbox.active | number" type="text" readonly>
|
||||
<span>Active</span>
|
||||
</ui-input>
|
||||
</ui-horizon-group>
|
||||
</section>
|
||||
<section>
|
||||
<ui-button @click="removeAllJobs">{{ $t('remove-all-jobs') }}</ui-button>
|
||||
</section>
|
||||
@@ -18,9 +46,26 @@ export default Vue.extend({
|
||||
|
||||
data() {
|
||||
return {
|
||||
stats: null
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
const fetchStats = () => {
|
||||
this.$root.api('admin/queue/stats', {}, true).then(stats => {
|
||||
this.stats = stats;
|
||||
});
|
||||
};
|
||||
|
||||
fetchStats();
|
||||
|
||||
const clock = setInterval(fetchStats, 1000);
|
||||
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
clearInterval(clock);
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
async removeAllJobs() {
|
||||
const process = async () => {
|
||||
|
16
src/index.ts
16
src/index.ts
@@ -73,7 +73,7 @@ function greet() {
|
||||
console.log(chalk.keyword('orange')(' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo'));
|
||||
|
||||
console.log('');
|
||||
console.log(chalk`<${os.hostname()} {gray (PID: ${process.pid.toString()})}>`);
|
||||
console.log(chalk`< ${os.hostname()} {gray (PID: ${process.pid.toString()})} >`);
|
||||
}
|
||||
|
||||
bootLogger.info('Welcome to Misskey!');
|
||||
@@ -117,9 +117,6 @@ async function masterMain() {
|
||||
await spawnWorkers(config.clusterLimit);
|
||||
}
|
||||
|
||||
// start queue
|
||||
require('./queue').default();
|
||||
|
||||
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
|
||||
}
|
||||
|
||||
@@ -130,6 +127,9 @@ async function workerMain() {
|
||||
// start server
|
||||
await require('./server').default();
|
||||
|
||||
// start job queue
|
||||
require('./queue').default();
|
||||
|
||||
if (cluster.isWorker) {
|
||||
// Send a 'ready' message to parent process
|
||||
process.send('ready');
|
||||
@@ -150,13 +150,9 @@ async function queueMain() {
|
||||
bootLogger.succ('Misskey initialized');
|
||||
|
||||
// start processor
|
||||
const queue = require('./queue').default();
|
||||
require('./queue').default();
|
||||
|
||||
if (queue) {
|
||||
bootLogger.succ('Queue started', null, true);
|
||||
} else {
|
||||
bootLogger.error('Queue not available');
|
||||
}
|
||||
bootLogger.succ('Queue started', null, true);
|
||||
}
|
||||
|
||||
const runningNodejsVersion = process.version.slice(1).split('.').map(x => parseInt(x, 10));
|
||||
|
@@ -19,6 +19,7 @@ Note.createIndex('userId');
|
||||
Note.createIndex('mentions');
|
||||
Note.createIndex('visibleUserIds');
|
||||
Note.createIndex('replyId');
|
||||
Note.createIndex('renoteId');
|
||||
Note.createIndex('tagsLower');
|
||||
Note.createIndex('_user.host');
|
||||
Note.createIndex('_files._id');
|
||||
|
@@ -21,9 +21,9 @@ function initializeQueue(name: string) {
|
||||
} : null);
|
||||
}
|
||||
|
||||
const deliverQueue = initializeQueue('deliver');
|
||||
const inboxQueue = initializeQueue('inbox');
|
||||
const dbQueue = initializeQueue('db');
|
||||
export const deliverQueue = initializeQueue('deliver');
|
||||
export const inboxQueue = initializeQueue('inbox');
|
||||
export const dbQueue = initializeQueue('db');
|
||||
|
||||
export function deliver(user: ILocalUser, content: any, to: any) {
|
||||
if (content == null) return null;
|
||||
@@ -118,8 +118,8 @@ export function createExportBlockingJob(user: ILocalUser) {
|
||||
|
||||
export default function() {
|
||||
if (!program.onlyServer) {
|
||||
deliverQueue.process(processDeliver);
|
||||
inboxQueue.process(processInbox);
|
||||
deliverQueue.process(128, processDeliver);
|
||||
inboxQueue.process(128, processInbox);
|
||||
processDb(dbQueue);
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ import instanceChart from '../../services/chart/instance';
|
||||
|
||||
let latest: string = null;
|
||||
|
||||
export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
export default async (job: Bull.Job): Promise<void> => {
|
||||
const { host } = new URL(job.data.to);
|
||||
|
||||
try {
|
||||
@@ -29,8 +29,6 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
|
||||
instanceChart.requestSent(i.host, true);
|
||||
});
|
||||
|
||||
done();
|
||||
} catch (res) {
|
||||
// Update stats
|
||||
registerOrFetchInstanceDoc(host).then(i => {
|
||||
@@ -51,13 +49,12 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
if (res.statusCode >= 400 && res.statusCode < 500) {
|
||||
// HTTPステータスコード4xxはクライアントエラーであり、それはつまり
|
||||
// 何回再送しても成功することはないということなのでエラーにはしないでおく
|
||||
done();
|
||||
} else {
|
||||
done(res.statusMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
return res.statusMessage;
|
||||
} else {
|
||||
queueLogger.warn(`deliver failed: ${res} to=${job.data.to}`);
|
||||
done();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -15,7 +15,7 @@ import instanceChart from '../../services/chart/instance';
|
||||
const logger = new Logger('inbox');
|
||||
|
||||
// ユーザーのinboxにアクティビティが届いた時の処理
|
||||
export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
export default async (job: Bull.Job): Promise<void> => {
|
||||
const signature = job.data.signature;
|
||||
const activity = job.data.activity;
|
||||
|
||||
@@ -33,7 +33,6 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
const { username, host } = parseAcct(keyIdLower.slice('acct:'.length));
|
||||
if (host === null) {
|
||||
logger.warn(`request was made by local user: @${username}`);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,7 +41,6 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
ValidateActivity(activity, host);
|
||||
} catch (e) {
|
||||
logger.warn(e.message);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -51,7 +49,6 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
const instance = await Instance.findOne({ host: host.toLowerCase() });
|
||||
if (instance && instance.isBlocked) {
|
||||
logger.warn(`Blocked request: ${host}`);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,7 +60,6 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
ValidateActivity(activity, host);
|
||||
} catch (e) {
|
||||
logger.warn(e.message);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -72,7 +68,6 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
const instance = await Instance.findOne({ host: host.toLowerCase() });
|
||||
if (instance && instance.isBlocked) {
|
||||
logger.warn(`Blocked request: ${host}`);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,7 +87,6 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
} else {
|
||||
updatePerson(activity.actor, null, activity.object);
|
||||
}
|
||||
done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -103,13 +97,11 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
}
|
||||
|
||||
if (user === null) {
|
||||
done(new Error('failed to resolve user'));
|
||||
return;
|
||||
throw new Error('failed to resolve user');
|
||||
}
|
||||
|
||||
if (!httpSignature.verifySignature(signature, user.publicKey.publicKeyPem)) {
|
||||
logger.error('signature verification failed');
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,12 +128,7 @@ export default async (job: Bull.Job, done: any): Promise<void> => {
|
||||
});
|
||||
|
||||
// アクティビティを処理
|
||||
try {
|
||||
await perform(user, activity);
|
||||
done();
|
||||
} catch (e) {
|
||||
done(e);
|
||||
}
|
||||
await perform(user, activity);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -14,7 +14,7 @@ import Instance from '../../models/instance';
|
||||
|
||||
export const logger = apLogger.createSubLogger('deliver');
|
||||
|
||||
export default (user: ILocalUser, url: string, object: any) => new Promise(async (resolve, reject) => {
|
||||
export default async (user: ILocalUser, url: string, object: any) => {
|
||||
logger.info(`--> ${url}`);
|
||||
|
||||
const timeout = 10 * 1000;
|
||||
@@ -32,53 +32,57 @@ export default (user: ILocalUser, url: string, object: any) => new Promise(async
|
||||
sha256.update(data);
|
||||
const hash = sha256.digest('base64');
|
||||
|
||||
const addr = await resolveAddr(hostname).catch(e => reject(e));
|
||||
const addr = await resolveAddr(hostname);
|
||||
if (!addr) return;
|
||||
|
||||
const req = request({
|
||||
protocol,
|
||||
hostname: addr,
|
||||
setHost: false,
|
||||
port,
|
||||
method: 'POST',
|
||||
path: pathname + search,
|
||||
timeout,
|
||||
headers: {
|
||||
'Host': host,
|
||||
'User-Agent': config.userAgent,
|
||||
'Content-Type': 'application/activity+json',
|
||||
'Digest': `SHA-256=${hash}`
|
||||
}
|
||||
}, res => {
|
||||
if (res.statusCode >= 400) {
|
||||
logger.warn(`${url} --> ${res.statusCode}`);
|
||||
reject(res);
|
||||
} else {
|
||||
logger.succ(`${url} --> ${res.statusCode}`);
|
||||
resolve();
|
||||
}
|
||||
const _ = new Promise((resolve, reject) => {
|
||||
const req = request({
|
||||
protocol,
|
||||
hostname: addr,
|
||||
setHost: false,
|
||||
port,
|
||||
method: 'POST',
|
||||
path: pathname + search,
|
||||
timeout,
|
||||
headers: {
|
||||
'Host': host,
|
||||
'User-Agent': config.userAgent,
|
||||
'Content-Type': 'application/activity+json',
|
||||
'Digest': `SHA-256=${hash}`
|
||||
}
|
||||
}, res => {
|
||||
if (res.statusCode >= 400) {
|
||||
logger.warn(`${url} --> ${res.statusCode}`);
|
||||
reject(res);
|
||||
} else {
|
||||
logger.succ(`${url} --> ${res.statusCode}`);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
sign(req, {
|
||||
authorizationHeaderName: 'Signature',
|
||||
key: user.keypair,
|
||||
keyId: `${config.url}/users/${user._id}/publickey`,
|
||||
headers: ['date', 'host', 'digest']
|
||||
});
|
||||
|
||||
// Signature: Signature ... => Signature: ...
|
||||
let sig = req.getHeader('Signature').toString();
|
||||
sig = sig.replace(/^Signature /, '');
|
||||
req.setHeader('Signature', sig);
|
||||
|
||||
req.on('timeout', () => req.abort());
|
||||
|
||||
req.on('error', e => {
|
||||
if (req.aborted) reject('timeout');
|
||||
reject(e);
|
||||
});
|
||||
|
||||
req.end(data);
|
||||
});
|
||||
|
||||
sign(req, {
|
||||
authorizationHeaderName: 'Signature',
|
||||
key: user.keypair,
|
||||
keyId: `${config.url}/users/${user._id}/publickey`,
|
||||
headers: ['date', 'host', 'digest']
|
||||
});
|
||||
|
||||
// Signature: Signature ... => Signature: ...
|
||||
let sig = req.getHeader('Signature').toString();
|
||||
sig = sig.replace(/^Signature /, '');
|
||||
req.setHeader('Signature', sig);
|
||||
|
||||
req.on('timeout', () => req.abort());
|
||||
|
||||
req.on('error', e => {
|
||||
if (req.aborted) reject('timeout');
|
||||
reject(e);
|
||||
});
|
||||
|
||||
req.end(data);
|
||||
await _;
|
||||
|
||||
//#region Log
|
||||
publishApLogStream({
|
||||
@@ -88,7 +92,7 @@ export default (user: ILocalUser, url: string, object: any) => new Promise(async
|
||||
actor: user.username
|
||||
});
|
||||
//#endregion
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve host (with cached, asynchrony)
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { performance } from 'perf_hooks';
|
||||
import limiter from './limiter';
|
||||
import { IUser } from '../../models/user';
|
||||
import { IApp } from '../../models/app';
|
||||
@@ -71,6 +72,7 @@ export default async (endpoint: string, user: IUser, app: IApp, data: any, file?
|
||||
}
|
||||
|
||||
// API invoking
|
||||
const before = performance.now();
|
||||
return await ep.exec(data, user, app, file).catch((e: Error) => {
|
||||
if (e instanceof ApiError) {
|
||||
throw e;
|
||||
@@ -88,5 +90,11 @@ export default async (endpoint: string, user: IUser, app: IApp, data: any, file?
|
||||
}
|
||||
});
|
||||
}
|
||||
}).finally(() => {
|
||||
const after = performance.now();
|
||||
const time = after - before;
|
||||
if (time > 1000) {
|
||||
apiLogger.warn(`SLOW API CALL DETECTED: ${ep.name} (${time}ms)`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
21
src/server/api/endpoints/admin/queue/stats.ts
Normal file
21
src/server/api/endpoints/admin/queue/stats.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import define from '../../../define';
|
||||
import { deliverQueue } from '../../../../../queue';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
params: {}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps) => {
|
||||
const deliverJobCounts = await deliverQueue.getJobCounts();
|
||||
const inboxJobCounts = await deliverQueue.getJobCounts();
|
||||
|
||||
return {
|
||||
deliver: deliverJobCounts,
|
||||
inbox: inboxJobCounts
|
||||
};
|
||||
});
|
Reference in New Issue
Block a user