Compare commits

...

63 Commits

Author SHA1 Message Date
Derek e7895eff10 Merge branch 'master' of https://github.com/misskey-dev/misskey 2021-06-23 08:44:07 -07:00
syuilo d04014f875 Merge branch 'develop' 2021-06-10 14:03:28 +09:00
syuilo e1247b3e45 12.83.0 2021-06-10 14:03:19 +09:00
syuilo 8b9c445fef
New Crowdin updates (#7554)
* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations api.md (Korean)

* New translations mfm.md (Korean)

* New translations api.md (Korean)

* New translations timelines.md (Spanish)

* New translations timelines.md (Spanish)

* New translations timelines.md (Spanish)

* New translations theme.md (Spanish)

* New translations ja-JP.yml (Chinese Simplified)

* New translations theme.md (Spanish)

* New translations theme.md (Spanish)

* New translations theme.md (Spanish)

* New translations theme.md (Spanish)

* New translations theme.md (Spanish)

* New translations theme.md (Spanish)

* New translations stream.md (Spanish)

* New translations stream.md (Spanish)

* New translations stream.md (Spanish)

* New translations stream.md (Spanish)
2021-06-10 14:01:09 +09:00
syuilo a65eb502d2 fix api response definition 2021-06-08 14:26:52 +09:00
syuilo 55c549a9f8 Remove entity descriptions
#6627
2021-06-08 14:24:21 +09:00
syuilo 56600ba1df refactor type 2021-06-08 14:14:58 +09:00
syuilo 6b312f755e Remove endpoint descriptions
#6627
2021-06-08 14:09:32 +09:00
syuilo d6267f797d 外部リンクアイコンが表示されない問題を修正 2021-06-08 12:19:55 +09:00
NoriDev a2b8097b4b
歓迎ページでバナー画像が表示されない問題を修正 (#7559)
* 歓迎ページでバナー画像が表示されない問題

* revert

* 背景画像設定オプションを追加
2021-06-08 12:17:17 +09:00
syuilo 22bbee1fa3 Update deps 2021-06-08 11:40:08 +09:00
mint fa1b38394c
Updated divisions to math.div (#7549)
* Updated divisions to math.div on Reversi (game.board.vue)

* Update src/client/pages/reversi/game.board.vue

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>

* Oops. Forgot to put it all through parenthesis

* Imported sass:math

* Fixes on drive.vue

* Forgot the stupid comma

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-06-05 14:57:52 +09:00
MeiMei 441790be2d
Fix resync-remote-user (#7556)
* Fix resync-remote-user

* tune
2021-06-05 14:55:41 +09:00
MeiMei 5d66bb8794
ランダムにテストがコケるのを修正 (#7553)
* Test shutdown

* Revert "Test shutdown"

This reverts commit 85182e7dd196cdd9ecb46cfb50adaabd04c5ba60.

* Skip beforeShutdown in test

* Wait shutdown in test

* Revert "Skip beforeShutdown in test"

This reverts commit 79c33ab53615e8fa4820d2abfc2494cba55c441c.

* Revert "Revert "Skip beforeShutdown in test""

This reverts commit 3423133a137c79b64f3ff6ef9dbe433a441a47b0.
2021-06-05 14:54:07 +09:00
MeiMei a5cdc9a1f4
Add missing migrations (#7552) 2021-06-04 20:40:47 +09:00
syuilo a5a2f9d01e Update misskey.js 2021-06-01 19:17:25 +09:00
syuilo 89fb727f61 Update type.ts 2021-06-01 19:17:17 +09:00
syuilo 929e545514 Merge branch 'develop' 2021-05-31 13:06:40 +09:00
syuilo 3e7a87f75a 12.82.0 2021-05-31 13:06:25 +09:00
MeiMei caf40e40fb
Supports Array ActivityStreams type (#7536)
* Supports Array type

* Fix

* Fix Service to Note

* Update type.ts

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-05-31 13:04:13 +09:00
syuilo b608f63a1a
New Crowdin updates (#7527)
* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Korean)
2021-05-31 12:02:13 +09:00
syuilo dc44d9a0a8 fix 2021-05-31 12:02:02 +09:00
syuilo bb926dd301 fix bug 2021-05-31 11:05:37 +09:00
syuilo 79cb836483 Update deps 2021-05-31 11:05:34 +09:00
syuilo f1c4e4a10e fix style 2021-05-31 10:35:12 +09:00
MeiMei 798aedfc0f
Supports Emoji 13.1 (#7539)
* Supports Emoji 13.1

* Fix regex
2021-05-30 20:52:39 +09:00
syuilo 1077c2a637 🎨 2021-05-30 16:42:22 +09:00
syuilo cbe689607c Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-05-30 16:27:00 +09:00
syuilo 948b70cb0f fix typo
Resolve #7540
2021-05-30 16:26:52 +09:00
MeiMei 0263539202
Fix remote drive expire (#7543) 2021-05-30 13:48:23 +09:00
syuilo 52e54cf0dc refactor 2021-05-30 10:05:25 +09:00
syuilo 24e7eeca0f fix local emoji detection
https://github.com/misskey-dev/misskey/pull/7526#discussion_r641886612
2021-05-30 10:05:12 +09:00
syuilo d76345264d fix bug 2021-05-28 22:57:04 +09:00
syuilo 0eb115bf7e Resolve #7538 2021-05-28 22:53:00 +09:00
syuilo 30d2a1d8b6 fix bug 2021-05-28 22:52:38 +09:00
syuilo 857c88e8d6 fix type 2021-05-28 22:52:30 +09:00
nullobsi ffb9646ce9
Add image description support (#7518)
* recieve image descriptions under the name property

* fix other components

* use comment for alt and title

* allow editing of file comment

* allow editing of file comment in note dialog

* federate note comments

* use file instead of this

* backend should accept comment on update

* update now actually accepts comment

* allow multiline descriptions

* image should also have description attached

* Update locales/ja-JP.yml

Co-authored-by: rinsuki <428rinsuki+git@gmail.com>

* Use custom component with side-by-side image

* improve usability on mobile devices

* revert changes

* Update post-form-attaches.vue

* Update drive.file.vue

* Update media-caption.vue

Co-authored-by: rinsuki <428rinsuki+git@gmail.com>
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-05-28 09:38:09 +09:00
syuilo db3724cf33 improve types 2021-05-28 09:34:42 +09:00
rinsuki 466c083233
カスタム絵文字をproxyに通すように (#7526) 2021-05-27 22:40:48 +09:00
syuilo ae2267220b wip #7533 2021-05-27 17:15:08 +09:00
syuilo c92744c3d3
Create SECURITY.md 2021-05-24 05:50:45 +09:00
syuilo 35f075b887 🎨 2021-05-23 21:28:41 +09:00
syuilo 6cc4edc5e8 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-05-23 21:14:44 +09:00
syuilo c06091f78a Update README.md 2021-05-23 21:14:29 +09:00
Sandy Nicko Mac Corzeta f85399e355
Add Indonesian to index language (#7528)
Co-authored-by: Sandy Nicko Mac Corzeta <sandynicko@windowslive.com>
2021-05-23 18:57:33 +09:00
MeiMei 47aaf04481
Fix search-by-tag (#7531)
* Fix search-by-tag

* Revert "Fix search-by-tag"

This reverts commit c971d1d5d82f2d8b58fdec76e42f4404339ab83a.

* Fix typo

* Remove unused var

* インジェクションは[]を返すように
2021-05-23 18:57:12 +09:00
okayurisotto 7063a6925f
fix: Safariでもモーダルのぼかし効果が効くようにした (#7530)
https://github.com/misskey-dev/misskey/issues/7529
2021-05-23 18:55:21 +09:00
MeiMei 3cd04c4b81
Fix agent type (#7532) 2021-05-23 13:07:11 +09:00
syuilo 942c802431 Merge branch 'develop' 2021-05-21 17:28:39 +09:00
syuilo e6754eb880 12.81.2 2021-05-21 17:28:19 +09:00
syuilo 70d02cf1be Merge branch 'develop' 2021-05-21 17:27:47 +09:00
syuilo ef646b9576 12.81.1 2021-05-21 17:27:17 +09:00
syuilo ecd541873b Update node version 2021-05-21 17:27:09 +09:00
syuilo 5d10642e07
New Crowdin updates (#7511)
* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations timelines.md (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations aiscript.md (Indonesian)

* New translations aiscript.md (Indonesian)

* New translations api.md (Indonesian)

* New translations api.md (Indonesian)

* New translations custom-emoji.md (Indonesian)

* New translations timelines.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations follow.md (Indonesian)

* New translations timelines.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations create-plugin.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations theme.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations stream.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations deck.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations theme.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations keyboard-shortcut.md (Indonesian)

* New translations pages.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations theme.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations reversi-bot.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Indonesian)
2021-05-21 17:20:45 +09:00
syuilo da34acd35f
Resolve #6563 (#7524)
* Resolve #6563

* Update note.ts

* Update generate-visibility-query.ts
2021-05-21 14:13:03 +09:00
syuilo 0108b8bfe3 Update deps 2021-05-20 12:27:50 +09:00
MeiMei b16c3798a4
Fix Announce/Delete AP deliver (#7517)
* Fix Announce/Delete AP deliver

* Revert "Fix Announce/Delete AP deliver"

This reverts commit 0292c5196df48f67bb7914e925560ba69e2b2980.

* localOnlyのDeleteをdeliverしないように

* null Activityに対するUndoはdeliverしないように
2021-05-19 16:15:01 +09:00
MeiMei 4b33c42da7
Add queue timeout (#7519) 2021-05-19 16:12:31 +09:00
MeiMei 961b3177d5
Fix Agent type, httpでもDNSキャッシュ (#7520) 2021-05-19 16:11:47 +09:00
MeiMei 7dc85a624e
Update preloaded JSON-LD (#7521) 2021-05-19 16:10:43 +09:00
MeiMei bfd215542b
@contextをちゃんと付ける (#7522) 2021-05-19 16:00:08 +09:00
syuilo d752275730 fix bug 2021-05-14 11:04:21 +09:00
syuilo be7e389bb5 Revert "fix bug"
This reverts commit 5b250c15f8.
2021-05-14 10:49:54 +09:00
349 changed files with 3355 additions and 3638 deletions

View File

@ -1 +1 @@
v16.0.0
v16.2.0

View File

@ -6,10 +6,6 @@ And is distributed under The GNU Affero General Public License Version 3, you sh
Misskey includes several third-party Open-Source softwares.
Unicode emoji regular expressions by Twitter, Inc.
License: MIT
https://github.com/twitter/twemoji-parser/blob/master/LICENSE.md
Emoji keywords for Unicode 11 and below by Mu-An Chiou
License: MIT
https://github.com/muan/emojilib/blob/master/LICENSE

View File

@ -1,4 +1,4 @@
FROM node:16.0.0-alpine3.13 AS base
FROM node:16.2.0-alpine3.13 AS base
ENV NODE_ENV=production

View File

@ -99,6 +99,11 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
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
:heart: Backers
----------------------------------------------------------------
<!-- PATREON_START -->

9
SECURITY.md Normal file
View File

@ -0,0 +1,9 @@
# Reporting Security Issues
If you discover a security issue in Misskey, please report it by sending an
email to [syuilotan@yahoo.co.jp](mailto:syuilotan@yahoo.co.jp).
This will allow us to assess the risk, and make a fix available before we add a
bug report to the GitHub repository.
Thanks for helping make Misskey safe for everyone.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

View File

@ -4,7 +4,7 @@
import * as fs from 'fs';
import * as gulp from 'gulp';
import * as rimraf from 'rimraf';
import rimraf from 'rimraf';
const replace = require('gulp-replace');
const terser = require('gulp-terser');
const cssnano = require('gulp-cssnano');

View File

@ -259,8 +259,6 @@ monthX: "{month}"
yearX: "{year}"
pages: "الصفحات"
integration: "دمج"
connectSerice: "أوصل"
disconnectSerice: "قطع الاتصال"
enableLocalTimeline: "تفعيل الخيط المحلي"
enableGlobalTimeline: "تفعيل الخيط الزمني الشامل"
disablingTimelinesInfo: "سيتمكن المسؤولون ومن تعديل دائمًا و من الوصول إلى جميع المخططات الزمنية ، حتى إذا لم يتم تمكينها."

View File

@ -269,8 +269,6 @@ monthX: "{month}"
yearX: "{year}"
pages: "Stránky"
integration: "Integrace"
connectSerice: "Připojit"
disconnectSerice: "Odpojit"
enableLocalTimeline: "Povolit lokální čas"
enableGlobalTimeline: "Povolit globální čas"
registration: "Registrace"

View File

@ -279,6 +279,7 @@ emptyDrive: "Drive ist leer"
emptyFolder: "Der Ordner ist leer"
unableToDelete: "Nicht löschbar"
inputNewFileName: "Gib einen neuen Dateinamen ein"
inputNewDescription: "Gib eine neue Beschreibung ein"
inputNewFolderName: "Gib einen neuen Ordnernamen ein"
circularReferenceFolder: "Der Zielordner ist ein Unterorder des Ordners, den du verschieben möchtest."
hasChildFilesOrFolders: "Dieser Ordner kann nicht gelöscht werden, da er nicht leer ist."
@ -310,8 +311,8 @@ monthX: "{month}"
yearX: "{year}"
pages: "Seiten"
integration: "Integration"
connectSerice: "Verbinden"
disconnectSerice: "Trennen"
connectService: "Verbinden"
disconnectService: "Trennen"
enableLocalTimeline: "Lokale Chronik aktivieren"
enableGlobalTimeline: "Globale Chronik aktivieren"
disablingTimelinesInfo: "Administratoren und Moderatoren haben immer Zugriff auf alle Chroniken, auch wenn diese deaktiviert sind."
@ -325,6 +326,7 @@ driveCapacityPerRemoteAccount: "Drive-Kapazität pro Benutzer anderer Instanzen"
inMb: "In Megabytes"
iconUrl: "Icon-URL"
bannerUrl: "Banner-URL"
backgroundImageUrl: "Hintergrundbild-URL"
basicInfo: "Basisdaten"
pinnedUsers: "Angepinnte Benutzer"
pinnedUsersDescription: "Gib einen Benutzernamen pro Zeile ein. Diese werden im \"Erkunden\" Tab angezeigt."
@ -546,6 +548,8 @@ disablePlayer: "Video-Player schließen"
expandTweet: "Tweet ausklappen"
themeEditor: "Farbthemen-Editor"
description: "Beschreibung"
describeFile: "Beschreibung hinzufügen"
enterFileDescription: "Beschreibung eingeben"
author: "Autor"
leaveConfirm: "Es gibt unspeicherte Änderungen. Möchtest du diese verwerfen?"
manage: "Verwaltung"
@ -731,9 +735,11 @@ active: "Aktiv"
offline: "Offline"
notRecommended: "Nicht empfohlen"
botProtection: "Bot-Schutz"
instanceBlocking: "Blockierte Instanzen"
selectAccount: "Benutzerkonto auswählen"
enabled: "Aktiviert"
disabled: "Deaktiviert"
quickAction: "Schnellaktionen"
user: "Benutzer"
administration: "Verwaltung"
accounts: "Benutzerkonten"

View File

@ -279,6 +279,7 @@ emptyDrive: "The drive is empty"
emptyFolder: "This folder is empty"
unableToDelete: "Unable to delete"
inputNewFileName: "Enter a new filename"
inputNewDescription: "Enter new caption"
inputNewFolderName: "Enter a new folder name"
circularReferenceFolder: "The destination folder is a subfolder of the folder you wish to move."
hasChildFilesOrFolders: "Since this folder is not empty, it can not be deleted."
@ -310,8 +311,8 @@ monthX: "{month}"
yearX: "{year} /"
pages: "Pages"
integration: "Integration"
connectSerice: "Connect"
disconnectSerice: "Disconnect"
connectService: "Connect"
disconnectService: "Disconnect"
enableLocalTimeline: "Enable local timeline"
enableGlobalTimeline: "Enable global timeline"
disablingTimelinesInfo: "Admins and Mods will always have access to all timelines, even if they are not enabled."
@ -325,6 +326,7 @@ driveCapacityPerRemoteAccount: "Drive capacity per remote user"
inMb: "In megabytes"
iconUrl: "Icon URL"
bannerUrl: "Banner image URL"
backgroundImageUrl: "Background image URL"
basicInfo: "Basic info"
pinnedUsers: "Pinned user"
pinnedUsersDescription: "List one username per line. Users listed here will be pinned under \"Explore\" tab."
@ -546,6 +548,8 @@ disablePlayer: "Close video player"
expandTweet: "Expand tweet"
themeEditor: "Theme editor"
description: "Description"
describeFile: "Add caption"
enterFileDescription: "Enter caption"
author: "Author"
leaveConfirm: "There are unsaved changes. Do you want to discard them?"
manage: "Management"

View File

@ -309,8 +309,6 @@ monthX: "Mes {month}"
yearX: "Año {year}"
pages: "Páginas"
integration: "Integración"
connectSerice: "Conectarse"
disconnectSerice: "Desconectarse"
enableLocalTimeline: "Habilitar linea de tiempo local"
enableGlobalTimeline: "Habilitar linea de tiempo global"
disablingTimelinesInfo: "Aunque se desactiven estas lineas de tiempo, por conveniencia el administrador y los moderadores pueden seguir usándolos"

View File

@ -279,6 +279,7 @@ emptyDrive: "Le Drive est vide"
emptyFolder: "Le dossier est vide"
unableToDelete: "Suppression impossible"
inputNewFileName: "Entrez un nouveau nom de fichier"
inputNewDescription: "Veuillez entrer une nouvelle description"
inputNewFolderName: "Entrez un nouveau nom de dossier"
circularReferenceFolder: "Le dossier de destination est un sous-dossier du dossier que vous souhaitez déplacer."
hasChildFilesOrFolders: "Impossible de supprimer ce dossier car il n'est pas vide."
@ -310,8 +311,8 @@ monthX: "{month}"
yearX: "{year}"
pages: "Pages"
integration: "Intégrations"
connectSerice: "Connecter"
disconnectSerice: "Déconnecter"
connectService: "Connexion"
disconnectService: "Déconnexion"
enableLocalTimeline: "Activer le fil local"
enableGlobalTimeline: "Activer le fil global"
disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur·rice·s et les modérateur·rice·s pourront toujours y accéder."
@ -546,6 +547,8 @@ disablePlayer: "Fermer le lecteur vidéo"
expandTweet: "Étendre le tweet"
themeEditor: "Éditeur de thèmes"
description: "Description"
describeFile: "Ajouter une description d'image"
enterFileDescription: "Saisissez une description"
author: "Auteur·rice"
leaveConfirm: "Vous avez des modifications non-sauvegardées. Voulez-vous les ignorer ?"
manage: "Gestion"

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@ const languages = [
'en-US',
'es-ES',
'fr-FR',
'id-ID',
'ja-JP',
'ja-KS',
'kab-KAB',

View File

@ -274,6 +274,7 @@ emptyDrive: "Il Drive è vuoto"
emptyFolder: "La cartella è vuota"
unableToDelete: "Eliminazione impossibile"
inputNewFileName: "Inserisci nome del nuovo file"
inputNewDescription: "Inserisci una nuova descrizione"
inputNewFolderName: "Inserisci nome della nuova cartella"
circularReferenceFolder: "La cartella di destinazione è una sottocartella della cartella che vuoi spostare."
hasChildFilesOrFolders: "Impossibile eliminare la cartella perché non è vuota"
@ -305,8 +306,8 @@ monthX: "{month}"
yearX: "{year}"
pages: "Pagine"
integration: "App collegate"
connectSerice: "Connetti"
disconnectSerice: "Disconnetti"
connectService: "Connessione"
disconnectService: "Disconnessione "
enableLocalTimeline: "Abilita Timeline locale"
enableGlobalTimeline: "Abilita Timeline federata"
disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e i moderatori potranno sempre accederci."
@ -533,6 +534,8 @@ disablePlayer: "Chiudi lettore video"
expandTweet: "Espandi tweet"
themeEditor: "Editor di temi"
description: "Descrizione"
describeFile: "Aggiungi una descrizione d'immagine"
enterFileDescription: "Inserisci descrizione"
author: "Autore"
leaveConfirm: "Ci sono delle modifiche ancora non salvate. Vuoi cancellarle?"
manage: "Gestione"

View File

@ -311,8 +311,8 @@ monthX: "{month}月"
yearX: "{year}年"
pages: "ページ"
integration: "連携"
connectSerice: "接続する"
disconnectSerice: "切断する"
connectService: "接続する"
disconnectService: "切断する"
enableLocalTimeline: "ローカルタイムラインを有効にする"
enableGlobalTimeline: "グローバルタイムラインを有効にする"
disablingTimelinesInfo: "これらのタイムラインを無効化しても、利便性のため管理者およびモデレーターは引き続き利用することができます。"
@ -326,6 +326,7 @@ driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのド
inMb: "メガバイト単位"
iconUrl: "アイコン画像のURL (faviconなど)"
bannerUrl: "バナー画像のURL"
backgroundImageUrl: "背景画像のURL"
basicInfo: "基本情報"
pinnedUsers: "ピン留めユーザー"
pinnedUsersDescription: "「みつける」ページなどにピン留めしたいユーザーを改行で区切って記述します。"

View File

@ -308,8 +308,6 @@ monthX: "{month}月"
yearX: "{year}年"
pages: "ページ"
integration: "連携"
connectSerice: "つなぐ"
disconnectSerice: "切ってまう"
enableLocalTimeline: "ローカルタイムラインを使えるようにする"
enableGlobalTimeline: "グローバルタイムラインを使えるようにする"
disablingTimelinesInfo: "ここらへんのタイムラインを使えんようにしてしもても、管理者とモデレーターは使えるままになってるで、そうやなかったら不便やからな。"

View File

@ -279,6 +279,7 @@ emptyDrive: "드라이브가 비어 있습니다"
emptyFolder: "폴더가 비어 있습니다"
unableToDelete: "삭제할 수 없습니다"
inputNewFileName: "바꿀 파일명을 입력해 주세요"
inputNewDescription: "새 캡션을 입력해 주세요"
inputNewFolderName: "바꿀 폴더명을 입력해 주세요"
circularReferenceFolder: "지정한 폴더가 이동할 폴더의 하위 폴더입니다."
hasChildFilesOrFolders: "이 폴더는 비어있지 않기 때문에 삭제할 수 없습니다."
@ -310,8 +311,8 @@ monthX: "{month}월"
yearX: "{year}년"
pages: "페이지"
integration: "연동"
connectSerice: "접속"
disconnectSerice: "연결 끊기"
connectService: "계정 연동"
disconnectService: "계정 연동 해제"
enableLocalTimeline: "로컬 타임라인 활성화"
enableGlobalTimeline: "글로벌 타임라인 활성화"
disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리자 및 모더레이터는 계속 사용할 수 있습니다."
@ -325,6 +326,7 @@ driveCapacityPerRemoteAccount: "리모트 유저 한 명당 드라이브 용량"
inMb: "메가바이트 단위"
iconUrl: "아이콘 URL"
bannerUrl: "배너 이미지 URL"
backgroundImageUrl: "배경 이미지 URL"
basicInfo: "기본 정보"
pinnedUsers: "고정된 유저"
pinnedUsersDescription: "\"발견하기\" 페이지 등에 고정하고 싶은 유저를 한 줄에 한 명씩 적습니다."
@ -546,6 +548,8 @@ disablePlayer: "플레이어 닫기"
expandTweet: "트윗 확장하기"
themeEditor: "테마 에디터"
description: "설명"
describeFile: "캡션 추가"
enterFileDescription: "캡션 입력"
author: "작성자"
leaveConfirm: "저장하지 않은 변경사항이 있습니다. 취소하시겠습니까?"
manage: "관리"

View File

@ -1,2 +1,3 @@
---
_lang_: "Nederlands"
headlineMisskey: "Netwerk verbonden door notities"

View File

@ -7,6 +7,7 @@ search: "Szukaj"
notifications: "Powiadomienia"
username: "Nazwa użytkownika"
password: "Hasło"
forgotPassword: "Nie pamiętam hasła"
fetchingAsApObject: "Pobieranie z Fediwersum…"
ok: "OK"
gotIt: "Rozumiem!"
@ -65,6 +66,7 @@ download: "Pobierz"
driveFileDeleteConfirm: "Czy chcesz usunąć plik \"{name}\"? Zniknie również notatka, do której dołączony jest ten plik."
unfollowConfirm: "Czy na pewno chcesz przestać obserwować {name}?"
exportRequested: "Zażądałeś eksportu. Może to zająć trochę czasu. Po zakończeniu eksportu zostanie on dodany do Twoich \"dysków\"."
importRequested: "Zażądano importu. Może to zająć chwilę."
lists: "Listy"
noLists: "Nie masz żadnych list"
note: "Utwórz wpis"
@ -133,9 +135,11 @@ settingGuide: "Proponowana konfiguracja"
cacheRemoteFiles: "Przechowuj zdalne pliki w pamięci podręcznej"
cacheRemoteFilesDescription: "Gdy ta opcja jest wyłączona, zdalne pliki są ładowane bezpośrednio ze zdalnych instancji. Wyłączenie the opcji zmniejszy użycie powierzchni dyskowej, ale zwiększy transfer, ponieważ miniaturki nie będą generowane."
flagAsBot: "To konto jest botem"
flagAsBotDescription: "Jeżeli ten kanał jest kontrolowany przez jakiś program, ustaw tę opcję. Jeżeli włączona, będzie działać jako flaga informująca innych programistów, aby zapobiegać nieskończonej interakcji z różnymi botami i dostosowywać wewnętrzne systemy Misskey, traktując konto jako bota."
flagAsCat: "To konto jest kotem"
flagAsCatDescription: "Przełącz tę opcję, aby konto było oznaczone jako kot."
autoAcceptFollowed: "Automatycznie przyjmuj prośby o możliwość obserwacji od użytkowników, których obserwujesz"
addAccount: "Dodaj konto"
loginFailed: "Nie udało się zalogować"
showOnRemote: "Zobacz na zdalnej instancji"
general: "Ogólne"
@ -179,6 +183,7 @@ clearQueueConfirmTitle: "Czy na pewno chcesz wyczyścić kolejkę?"
clearCachedFiles: "Wyczyść pamięć podręczną"
clearCachedFilesConfirm: "Czy na pewno chcesz usunąć wszystkie zdalne pliki z pamięci podręcznej?"
blockedInstances: "Zablokowane instancje"
blockedInstancesDescription: "Wypisz nazwy hostów instancji, które powinny zostać zablokowane. Wypisane instancje nie będą mogły dłużej komunikować się z tą instancją."
muteAndBlock: "Wycisz / Zablokuj"
mutedUsers: "Wyciszeni użytkownicy"
blockedUsers: "Zablokowani użytkownicy"
@ -271,6 +276,7 @@ emptyDrive: "Dysk jest pusty"
emptyFolder: "Ten katalog jest pusty"
unableToDelete: "Nie można usunąć"
inputNewFileName: "Wprowadź nową nazwę pliku"
inputNewDescription: "Proszę wpisać nowy napis"
inputNewFolderName: "Wprowadź nową nazwę katalogu"
circularReferenceFolder: "Katalog docelowy jest podkatalogiem katalogu, który chcesz przenieść."
hasChildFilesOrFolders: "Ponieważ ten katalog nie jest pusty, nie może być usunięty."
@ -291,16 +297,17 @@ reject: "Odrzuć"
normal: "Normalny"
instanceName: "Nazwa instancji"
instanceDescription: "Opis instancji"
maintainerName: "Administrator"
maintainerEmail: "E-mail administratora"
tosUrl: "Adres URL regulaminu"
thisYear: "Rok"
thisMonth: "Miesiąc"
today: "Dziś"
dayX: "{day}"
monthX: "{month}"
yearX: "{year}"
pages: "Strony"
integration: "Integracja"
connectSerice: "Połącz"
disconnectSerice: "Rozłącz"
enableLocalTimeline: "Włącz lokalną oś czasu"
enableGlobalTimeline: "Włącz globalną oś czasu"
disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do wszystkich osi czasu, nawet gdy są one wyłączone."
@ -332,6 +339,7 @@ manageAntennas: "Zarządzaj Antenami"
name: "Nazwa"
antennaSource: "Źródło Anteny"
antennaExcludeKeywords: "Wykluczone słowa kluczowe"
notifyAntenna: "Powiadamiaj o nowych wpisach"
withFileAntenna: "Filtruj tylko wpisy z załączonym plikiem"
enableServiceworker: "Włącz ServiceWorker"
antennaUsersDescription: "Wypisz po jednej nazwie użytkownika w linii"
@ -358,6 +366,7 @@ administrator: "Admin"
token: "Token"
twoStepAuthentication: "Uwierzytelnianie dwuskładnikowe"
moderator: "Moderator"
nUsersMentioned: "{n} wspomnianych użytkowników"
securityKey: "Klucz bezpieczeństwa"
securityKeyName: "Nazwa klucza"
registerSecurityKey: "Zarejestruj klucz bezpieczeństwa"
@ -397,6 +406,7 @@ retype: "Wprowadź ponownie"
noteOf: "Wpisy {user}"
inviteToGroup: "Zaproś do grupy"
maxNoteTextLength: "Limit znaków dla wpisów"
quoteAttached: "Zacytowano"
quoteQuestion: "Czy na pewno chcesz umieścić cytat?"
noMessagesYet: "Nie napisano jeszcze wiadomości"
newMessageExists: "Masz nową wiadomość"
@ -419,6 +429,7 @@ signinWith: "Zaloguj się z {x}"
signinFailed: "Nie udało się zalogować. Wprowadzona nazwa użytkownika lub hasło są nieprawidłowe."
tapSecurityKey: "Wybierz swój klucz bezpieczeństwa"
or: "Lub"
language: "Język"
uiLanguage: "Język wyświetlania UI"
groupInvited: "Zaproszony(-a) do grupy"
aboutX: "O {x}"
@ -432,6 +443,7 @@ category: "Kategoria"
tags: "Tagi"
docSource: "Źródło tego dokumentu"
createAccount: "Utwórz konto"
existingAccount: "Istniejące konto"
regenerate: "Wygeneruj ponownie"
fontSize: "Rozmiar czcionki"
noFollowRequests: "Nie masz żadnych oczekujących próśb o możliwość obserwacji"
@ -453,6 +465,8 @@ showFeaturedNotesInTimeline: "Pokazuj wyróżnione wpisy w osi czasu"
objectStorage: "Pamięć obiektowa"
useObjectStorage: "Używaj pamięci obiektowej"
objectStorageBaseUrl: "Podstawowy URL"
objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Podaj nazwę „wiadra” używaną przez konfigurowaną usługę."
objectStoragePrefix: "Prefiks"
objectStoragePrefixDesc: "Pliki będą przechowywane w katalogu z tym prefiksem."
objectStorageEndpoint: "Punkt końcowy"
@ -519,6 +533,8 @@ disablePlayer: "Zamknij odtwarzacz wideo"
expandTweet: "Rozwiń tweet"
themeEditor: "Edytor motywu"
description: "Opis"
describeFile: "dodaj podpis"
enterFileDescription: "Wprowadź napis"
author: "Autor"
leaveConfirm: "Są niezapisane zmiany. Czy chcesz je odrzucić?"
manage: "Zarządzanie"
@ -540,6 +556,7 @@ pluginTokenRequestedDescription: "Ta wtyczka będzie mogła korzystać z ustawio
notificationType: "Rodzaj powiadomień"
edit: "Edytuj"
useStarForReactionFallback: "Użyj ★ jako zapasowego emoji, gdy emoji reakcji jest nieznane"
emailServer: "Serwer poczty e-mail"
enableEmail: "Włącz dostarczanie wiadomości e-mail"
emailConfigInfo: "Wykorzystywany do potwierdzenia adresu e-mail w trakcie rejestracji, lub gdy zapomnisz hasła"
email: "Adres e-mail"
@ -552,6 +569,7 @@ smtpPass: "Hasło"
emptyToDisableSmtpAuth: "Pozostaw adres e-mail i hasło puste, aby wyłączyć weryfikację SMTP"
smtpSecureInfo: "Wyłącz, jeżeli używasz STARTTLS"
testEmail: "Przetestuj dostarczanie wiadomości e-mail"
wordMute: "Wyciszenie słowa"
userSaysSomething: "{name} powiedział(-a) coś"
makeActive: "Aktywuj"
display: "Wyświetlanie"
@ -622,6 +640,7 @@ emailVerified: "Adres e-mail został potwierdzony"
noteFavoritesCount: "Liczba polubionych wpisów"
pageLikesCount: "Liczba otrzymanych polubień stron"
pageLikedCount: "Liczba polubionych stron"
reversiCount: "Liczba rozgrywek Reversi"
contact: "Kontakt"
useSystemFont: "Używaj domyślnej czcionki systemu"
experimentalFeatures: "Eksperymentalne funkcje"
@ -630,6 +649,7 @@ makeExplorable: "Pokazuj konto na stronie „Eksploruj”"
makeExplorableDescription: "Jeżeli wyłączysz tę opcję, Twoje konto nie będzie wyświetlać się w sekcji „Eksploruj”."
showGapBetweenNotesInTimeline: "Pokazuj odstęp między wpisami na osi czasu."
duplicate: "Duplikuj"
left: "Lewo"
center: "Wyśsrodkuj"
wide: "Szerokie"
narrow: "Wąskie"
@ -639,26 +659,107 @@ clearCache: "Wyczyść pamięć podręczną"
onlineUsersCount: "{n} osób jest online"
nUsers: "{n} użytkowników"
nNotes: "{n} wpisów"
sendErrorReports: "Wyślij raporty o błędach"
myTheme: "Mój motyw"
backgroundColor: "Tło"
accentColor: "Akcent"
textColor: "Tekst"
saveAs: "Zapisz jako…"
advanced: "Zaawansowane"
value: "Wartość"
createdAt: "Utworzono"
updatedAt: "Zaktualizowano"
saveConfirm: "Zapisać zmiany?"
deleteConfirm: "Na pewno usunąć?"
invalidValue: "Nieprawidłowa wartość."
registry: "Rejestr"
closeAccount: "Zamknij konto"
currentVersion: "Bieżąca wersja"
latestVersion: "Najnowsza wersja"
youAreRunningUpToDateClient: "Korzystasz z najnowszej wersji klienta."
newVersionOfClientAvailable: "Nowsza wersja klienta jest dostępna."
usageAmount: "Użycie"
capacity: "Pojemność"
inUse: "Użyto"
editCode: "Edytuj kod"
apply: "Zastosuj"
receiveAnnouncementFromInstance: "Otrzymuj powiadomienia e-mail z tej instancji"
emailNotification: "Powiadomienia e-mail"
publish: "Publikuj"
inChannelSearch: "Szukaj na kanale"
useReactionPickerForContextMenu: "Otwórz wybornik reakcji prawym kliknięciem"
typingUsers: "{users} pisze(-ą)..."
jumpToSpecifiedDate: "Przejdź do określonej daty"
showingPastTimeline: "Obecnie wyświetla starą oś czasu"
clear: "Wróć"
markAllAsRead: "Oznacz wszystkie jako przeczytane"
goBack: "Wróć"
unlikeConfirm: "Na pewno chcesz usunąć polubienie?"
fullView: "Pełny widok"
quitFullView: "Opuść pełny widok"
addDescription: "Dodaj opis"
info: "Informacje"
userInfo: "Informacje o użykowniku"
unknown: "Nieznane"
onlineStatus: "Status online"
hideOnlineStatus: "Ukryj status online"
hideOnlineStatusDescription: "Ukrywanie statusu online ogranicza wygody niektórych funkcji, tj. wyszukiwanie"
online: "Online"
active: "Aktywny"
offline: "Offline"
notRecommended: "Nie zalecane"
botProtection: "Zabezpieczenie przed botami"
instanceBlocking: "Zablokowane instancje"
selectAccount: "Wybierz konto"
enabled: "Właczono"
disabled: "Wyłączono"
quickAction: "Szybkie działania"
user: "Użytkownicy"
administration: "Zarządzanie"
accounts: "Konta"
switch: "Przełącz"
noMaintainerInformationWarning: "Informacje o administratorze nie są skonfigurowane."
noBotProtectionWarning: "Zabezpieczenie przed botami nie jest skonfigurowane."
configure: "Skonfiguruj"
postToGallery: "Opublikuj w galerii"
gallery: "Galeria"
recentPosts: "Ostatnie wpisy"
popularPosts: "Popularne wpisy"
shareWithNote: "Udostępnij z wpisem"
ads: "Reklamy"
expiration: "Ankieta kończy się"
memo: "Notatki"
priority: "Priorytet"
high: "Wysoki"
middle: "Średnie"
low: "Niski"
emailNotConfiguredWarning: "Nie podano adresu e-mail"
ratio: "Stosunek"
_ad:
back: "Wróć"
reduceFrequencyOfThisAd: "Pokazuj tę reklamę rzadziej"
_forgotPassword:
ifNoEmail: "Jeżeli nie podano adresu e-mail podczas rejestracji, skontaktuj się z administratorem zamiast tego."
contactAdmin: "Jeżeli Twoja instancja nie obsługuje adresów e-mail, skontaktuj się zamiast tego z administratorem, aby zresetować hasło."
_gallery:
my: "Moja galeria"
liked: "Polubione wpisy"
like: "Polub"
unlike: "Cofnij polubienie"
_email:
_follow:
title: "Zaobserwował(a) Cię"
_receiveFollowRequest:
title: "Otrzymano prośbę o możliwość obserwacji"
_plugin:
install: "Zainstaluj wtyczki"
installWarn: "Nie instaluj niezaufanych wtyczek."
manage: "Zarządzanie wtyczkami"
_registry:
scope: "Zakres"
key: "Klucz"
keys: "Klucz"
domain: "Domena"
createKey: "Utwórz klucz"
_aboutMisskey:
about: "Misskey jest oprogramowanie open source rozwijanym przez syuilo od 2014."
@ -708,6 +809,7 @@ _mfm:
x4Description: "Czyni treść jeszcze większą niż jeszcze większa."
blur: "Rozmycie"
font: "Czcionka"
fontDescription: "Wybiera czcionkę do wyświetlania treści."
_reversi:
reversi: "Reversi"
gameSettings: "Ustawienia gry"
@ -972,16 +1074,21 @@ _profile:
username: "Nazwa użytkownika"
description: "Opis"
youCanIncludeHashtags: "Możesz umieścić hashtagi w swoim opisie."
metadata: "Dodatkowe informacje"
metadataEdit: "Edytuj dodatkowe informacje"
metadataDescription: "Możesz wyświetlać do czterech sekcji dodatkowych informacji na swoim profilu."
metadataLabel: "Etykieta"
metadataContent: "Treść"
changeAvatar: "Zmień awatar"
changeBanner: "Zmień baner"
_exportOrImport:
allNotes: "Wszystkie wpisy"
followingList: "Obserwowani"
muteList: "Wycisz"
blockingList: "Zablokuj"
userLists: "Listy"
_charts:
federationInstancesTotal: "Łącznie sfederowanych instancji"
usersTotal: "Łącznie # użytkowników"
activeUsers: "Aktywni użytkownicy"
_instanceCharts:
@ -996,6 +1103,7 @@ _instanceCharts:
_timelines:
home: "Strona główna"
local: "Lokalne"
social: "Społeczność"
global: "Globalna"
_rooms:
roomOf: "Pokój {user}"
@ -1366,6 +1474,8 @@ _deck:
swapRight: "Przesuń w prawo"
swapUp: "Zamień z powyższym"
swapDown: "Zamień z poniższym"
stackLeft: "Przypnij do lewej"
popRight: "Odepnij w prawo"
profile: "Profil"
_columns:
main: "Główna"

View File

@ -309,8 +309,6 @@ monthX: "{month} месяц"
yearX: "{year} год"
pages: "Страницы"
integration: "Интеграция"
connectSerice: "Соединение"
disconnectSerice: "Отключение"
enableLocalTimeline: "Включить локальную ленту"
enableGlobalTimeline: "Включить глобальную ленту"
disablingTimelinesInfo: "У администраторов и модераторов есть доступ ко всем лентам, даже если они отключены."

View File

@ -307,8 +307,6 @@ monthX: "{month}"
yearX: "{year}"
pages: "Сторінки"
integration: "Інтеграція"
connectSerice: "Під’єднати"
disconnectSerice: "Відключитися"
enableLocalTimeline: "Увімкнути локальну стрічку"
enableGlobalTimeline: "Увімкнути глобальну стрічку"
disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх стрічок, навіть якщо вони вимкнуті."

View File

@ -279,6 +279,7 @@ emptyDrive: "驱动器为空"
emptyFolder: "空文件夹"
unableToDelete: "无法删除"
inputNewFileName: "请输入新文件名"
inputNewDescription: "请输入新标题"
inputNewFolderName: "请输入新文件名"
circularReferenceFolder: "目标文件夹是您要移动的文件夹的子文件夹。"
hasChildFilesOrFolders: "此文件夹不为空,无法删除。"
@ -310,8 +311,8 @@ monthX: "{month}月"
yearX: "{year}年"
pages: "页面"
integration: "关联"
connectSerice: "连接"
disconnectSerice: "断开连接"
connectService: "连接"
disconnectService: "断开连接"
enableLocalTimeline: "启用本地时间线功能"
enableGlobalTimeline: "启用全局时间线"
disablingTimelinesInfo: "即使时间线功能被禁用,出于便利性的原因,管理员和数据图表也可以继续使用。"
@ -325,6 +326,7 @@ driveCapacityPerRemoteAccount: "每个远程用户的网盘容量"
inMb: "以兆字节(MegaByte)为单位"
iconUrl: "图标URL"
bannerUrl: "Banner URL"
backgroundImageUrl: "背景图URL"
basicInfo: "基本信息"
pinnedUsers: "置顶用户"
pinnedUsersDescription: "在「发现」页面中使用换行标记想要置顶的用户。"
@ -546,6 +548,8 @@ disablePlayer: "关闭播放器"
expandTweet: "展开贴文"
themeEditor: "主题编辑器"
description: "描述"
describeFile: "添加标题"
enterFileDescription: "输入标题"
author: "作者"
leaveConfirm: "存在未保存的更改。要放弃更改吗?"
manage: "管理"

View File

@ -1,18 +1,19 @@
---
_lang_: "繁體中文"
headlineMisskey: "貼文連繫網"
introMisskey: "歡迎! Misskey是一個開源且去中心化的社群網絡。\n通過「貼文」分享周邊新鮮事,並告訴其他人您的想法!📡\n透過「情感」功能對大家的貼文表達情感👍\n一起來探索這個新的世界吧🚀"
headlineMisskey: "貼文連繫網"
introMisskey: "歡迎! Misskey是一個開放原始碼且去中心化的社群網路。\n透過「貼文」分享周邊新鮮事,並告訴其他人您的想法!📡\n透過「情感」功能對大家的貼文表達情感👍\n一起來探索這個新的世界吧🚀"
monthAndDay: "{month}月 {day}日"
search: "搜尋"
notifications: "通知"
username: "使用者名稱"
password: "密碼"
forgotPassword: "忘記密碼"
fetchingAsApObject: "從聯邦宇宙取得中..."
ok: "OK"
gotIt: "知道了"
cancel: "取消"
enterUsername: "輸入使用者名稱"
renotedBy: "{user} 轉了"
renotedBy: "{user} 轉了"
noNotes: "貼文不可用。"
noNotifications: "沒有通知"
instance: "實例"
@ -92,9 +93,9 @@ followRequestPending: "追隨許可批准中"
enterEmoji: "輸入表情符號"
renote: "轉發"
unrenote: "取消轉發"
renoted: "轉成功"
renoted: "轉成功"
cantRenote: "無法轉發此貼文。"
cantReRenote: "無法轉發之前已經轉發過的內容。"
cantReRenote: "無法轉傳之前已經轉傳過的內容。"
quote: "引用"
pinnedNote: "已置頂的貼文"
pinned: "置頂"
@ -309,8 +310,6 @@ monthX: "{month}月"
yearX: "{year}年"
pages: "頁面"
integration: "整合"
connectSerice: "連線"
disconnectSerice: "中斷連線"
enableLocalTimeline: "開啟本地時間軸"
enableGlobalTimeline: "啟用公開時間軸"
disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和協調人仍可以繼續使用,以方便您。"
@ -733,6 +732,7 @@ noBotProtectionWarning: "尚未設定Bot防護。"
configure: "設定"
expiration: "期限"
middle: "中"
emailNotConfiguredWarning: "沒有設定電子郵件地址"
_ad:
back: "返回"
_gallery:

View File

@ -0,0 +1,16 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class addNoteIndexes1621479946000 implements MigrationInterface {
name = 'addNoteIndexes1621479946000'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE INDEX "IDX_NOTE_MENTIONS" ON "note" USING gin ("mentions")`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_NOTE_VISIBLE_USER_IDS" ON "note" USING gin ("visibleUserIds")`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_NOTE_MENTIONS"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_NOTE_VISIBLE_USER_IDS"`, undefined);
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class userProfileDescriptionLength1622679304522 implements MigrationInterface {
name = 'userProfileDescriptionLength1622679304522';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "description" TYPE character varying(2048)`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "description" TYPE character varying(1024)`, undefined);
}
}

View File

@ -0,0 +1,12 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class logMessageLength1622681548499 implements MigrationInterface {
name = 'logMessageLength1622681548499';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "log" ALTER COLUMN "message" TYPE character varying(2048)`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "log" ALTER COLUMN "message" TYPE character varying(1024)`, undefined);
}
}

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.81.0",
"version": "12.83.0",
"codename": "indigo",
"repository": {
"type": "git",
@ -30,51 +30,52 @@
"format": "gulp format"
},
"resolutions": {
"mfm-js/twemoji-parser": "13.1.x",
"chokidar": "^3.3.1",
"constantinople": "^4.0.1",
"jsonld/rdf-canonize/node-forge": "0.10.0",
"lodash": "^4.17.20"
},
"dependencies": {
"@babel/plugin-transform-runtime": "7.13.15",
"@babel/plugin-transform-runtime": "7.14.3",
"@elastic/elasticsearch": "7.11.0",
"@koa/cors": "3.1.0",
"@koa/multer": "3.0.0",
"@koa/router": "9.0.1",
"@sentry/browser": "5.29.2",
"@sentry/tracing": "5.29.2",
"@sinonjs/fake-timers": "7.0.5",
"@sinonjs/fake-timers": "7.1.2",
"@syuilo/aiscript": "0.11.1",
"@types/bcryptjs": "2.4.2",
"@types/bull": "3.15.1",
"@types/cbor": "5.0.1",
"@types/cbor": "6.0.0",
"@types/dateformat": "3.0.1",
"@types/escape-regexp": "0.0.0",
"@types/glob": "7.1.3",
"@types/gulp": "4.0.8",
"@types/gulp-rename": "2.0.0",
"@types/is-url": "1.2.28",
"@types/is-url": "1.2.29",
"@types/js-yaml": "4.0.1",
"@types/jsdom": "16.2.10",
"@types/jsonld": "1.5.5",
"@types/katex": "0.11.0",
"@types/koa": "2.13.1",
"@types/koa-bodyparser": "4.3.0",
"@types/koa": "2.13.3",
"@types/koa-bodyparser": "4.3.1",
"@types/koa-cors": "0.0.0",
"@types/koa-favicon": "2.0.19",
"@types/koa-logger": "3.1.1",
"@types/koa-mount": "4.0.0",
"@types/koa-send": "4.1.2",
"@types/koa-views": "2.0.4",
"@types/koa-views": "7.0.0",
"@types/koa__cors": "3.0.2",
"@types/koa__multer": "2.0.2",
"@types/koa__router": "8.0.4",
"@types/markdown-it": "12.0.1",
"@types/matter-js": "0.14.11",
"@types/markdown-it": "12.0.2",
"@types/matter-js": "0.14.12",
"@types/mocha": "8.2.2",
"@types/node": "14.14.41",
"@types/node": "15.12.2",
"@types/node-fetch": "2.5.10",
"@types/nodemailer": "6.4.1",
"@types/nodemailer": "6.4.2",
"@types/nprogress": "0.2.0",
"@types/oauth": "0.9.1",
"@types/parse5": "6.0.0",
@ -85,12 +86,12 @@
"@types/qrcode": "1.4.0",
"@types/random-seed": "0.3.3",
"@types/ratelimiter": "3.4.1",
"@types/redis": "2.8.28",
"@types/rename": "1.0.2",
"@types/redis": "2.8.29",
"@types/rename": "1.0.3",
"@types/request-stats": "3.0.0",
"@types/rimraf": "3.0.0",
"@types/seedrandom": "2.4.28",
"@types/sharp": "0.28.0",
"@types/sharp": "0.28.3",
"@types/sinonjs__fake-timers": "6.0.2",
"@types/speakeasy": "2.0.5",
"@types/throttle-debounce": "2.1.0",
@ -101,46 +102,46 @@
"@types/webpack": "5.28.0",
"@types/webpack-stream": "3.2.12",
"@types/websocket": "1.0.2",
"@types/ws": "7.4.1",
"@typescript-eslint/parser": "4.22.0",
"@vue/compiler-sfc": "3.0.11",
"@types/ws": "7.4.4",
"@typescript-eslint/parser": "4.26.1",
"@vue/compiler-sfc": "3.1.1",
"abort-controller": "3.0.0",
"apexcharts": "3.26.1",
"apexcharts": "3.27.1",
"autobind-decorator": "2.4.0",
"autosize": "4.0.2",
"autosize": "4.0.4",
"autwh": "0.1.0",
"aws-sdk": "2.892.0",
"aws-sdk": "2.923.0",
"bcryptjs": "2.4.3",
"blurhash": "1.1.3",
"broadcast-channel": "3.5.3",
"bull": "3.22.3",
"broadcast-channel": "3.6.0",
"bull": "3.22.7",
"cafy": "15.2.1",
"cbor": "7.0.5",
"chalk": "4.1.1",
"chart.js": "2.9.4",
"cli-highlight": "2.1.11",
"commander": "7.2.0",
"concurrently": "6.0.2",
"concurrently": "6.2.0",
"content-disposition": "0.5.3",
"core-js": "3.11.0",
"core-js": "3.14.0",
"crc-32": "1.2.0",
"css-loader": "5.2.4",
"cssnano": "5.0.1",
"css-loader": "5.2.6",
"cssnano": "5.0.5",
"dateformat": "4.5.1",
"diskusage": "1.1.3",
"escape-regexp": "0.0.1",
"eslint": "7.25.0",
"eslint-plugin-vue": "7.9.0",
"eslint": "7.28.0",
"eslint-plugin-vue": "7.10.0",
"eventemitter3": "4.0.7",
"feed": "4.2.2",
"file-type": "16.3.0",
"file-type": "16.5.0",
"fluent-ffmpeg": "2.1.2",
"glob": "7.1.6",
"glob": "7.1.7",
"got": "11.8.2",
"gulp": "4.0.2",
"gulp-cssnano": "2.1.3",
"gulp-rename": "2.0.0",
"gulp-replace": "1.1.1",
"gulp-replace": "1.1.3",
"gulp-terser": "2.0.1",
"gulp-tslint": "8.1.4",
"hard-source-webpack-plugin": "0.13.1",
@ -148,17 +149,17 @@
"http-proxy-agent": "4.0.1",
"http-signature": "1.3.5",
"https-proxy-agent": "5.0.0",
"idb-keyval": "5.0.5",
"idb-keyval": "5.0.6",
"insert-text-at-cursor": "0.3.0",
"is-root": "2.1.0",
"is-svg": "4.3.1",
"js-yaml": "4.1.0",
"jsdom": "16.5.3",
"jsdom": "16.6.0",
"json5": "2.2.0",
"json5-loader": "4.0.1",
"jsonld": "4.0.1",
"jsrsasign": "8.0.20",
"katex": "0.13.3",
"katex": "0.13.11",
"koa": "2.13.1",
"koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0",
@ -173,23 +174,24 @@
"markdown-it": "12.0.6",
"markdown-it-anchor": "7.1.0",
"matter-js": "0.17.1",
"mfm-js": "0.16.3",
"mocha": "8.3.2",
"mfm-js": "0.18.0",
"misskey-js": "0.0.4",
"mocha": "8.4.0",
"moji": "0.5.1",
"ms": "2.1.3",
"multer": "1.4.2",
"nested-property": "4.0.0",
"node-fetch": "2.6.1",
"nodemailer": "6.5.0",
"nodemailer": "6.6.1",
"object-assign-deep": "0.4.0",
"os-utils": "0.0.14",
"parse5": "6.0.1",
"pg": "8.6.0",
"portscanner": "2.2.0",
"postcss": "8.2.12",
"postcss-loader": "5.2.0",
"postcss": "8.3.0",
"postcss-loader": "5.3.0",
"prismjs": "1.23.0",
"probe-image-size": "7.1.0",
"probe-image-size": "7.2.1",
"promise-limit": "2.7.0",
"promise-sequential": "1.1.1",
"pug": "3.0.2",
@ -198,7 +200,7 @@
"qrcode": "1.4.4",
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
"re2": "1.15.9",
"re2": "1.16.0",
"reconnecting-websocket": "4.4.0",
"redis": "3.1.2",
"redis-lock": "0.1.4",
@ -210,35 +212,36 @@
"rimraf": "3.0.2",
"rndstr": "1.0.0",
"s-age": "1.1.2",
"sass": "1.32.11",
"sass-loader": "11.0.1",
"sass": "1.34.1",
"sass-loader": "12.0.0",
"seedrandom": "3.0.5",
"sharp": "0.28.1",
"sharp": "0.28.3",
"speakeasy": "2.0.0",
"stringz": "2.1.0",
"style-loader": "2.0.0",
"summaly": "2.4.0",
"syslog-pro": "1.0.0",
"systeminformation": "5.6.12",
"systeminformation": "5.7.4",
"syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0",
"three": "0.117.1",
"throttle-debounce": "3.0.1",
"tinycolor2": "1.4.2",
"tmp": "0.2.1",
"ts-loader": "9.1.1",
"ts-node": "9.1.1",
"tsc-alias": "1.2.10",
"ts-loader": "9.2.3",
"ts-node": "10.0.0",
"tsc-alias": "1.3.2",
"tsconfig-paths": "3.9.0",
"tslint": "6.1.3",
"tslint-sonarts": "1.9.0",
"typeorm": "0.2.32",
"typescript": "4.2.4",
"twemoji-parser": "13.1.0",
"typeorm": "0.2.34",
"typescript": "4.3.2",
"ulid": "2.3.0",
"uuid": "8.3.2",
"v-debounce": "0.1.2",
"vanilla-tilt": "1.7.0",
"vue": "3.0.11",
"vue": "3.1.1",
"vue-color": "2.8.1",
"vue-json-pretty": "1.7.1",
"vue-loader": "16.1.2",
@ -248,10 +251,10 @@
"vue-svg-loader": "0.17.0-beta.2",
"vuedraggable": "4.0.1",
"web-push": "3.4.4",
"webpack": "5.35.1",
"webpack-cli": "4.6.0",
"webpack": "5.38.1",
"webpack-cli": "4.7.2",
"websocket": "1.0.34",
"ws": "7.4.5",
"ws": "7.4.6",
"xev": "2.0.1"
},
"devDependencies": {

View File

@ -1,11 +1,11 @@
<script lang="ts">
import { defineComponent, h, TransitionGroup } from 'vue';
import { defineComponent, h, PropType, TransitionGroup } from 'vue';
import MkAd from '@client/components/global/ad.vue';
export default defineComponent({
props: {
items: {
type: Array,
type: Array as PropType<{ id: string; createdAt: string; _shouldInsertAd_: boolean; }[]>,
required: true,
},
direction: {

View File

@ -139,7 +139,7 @@ export default defineComponent({
});
}
this.connection = os.stream.useSharedConnection('drive');
this.connection = os.stream.useChannel('drive');
this.connection.on('fileCreated', this.onStreamDriveFileCreated);
this.connection.on('fileUpdated', this.onStreamDriveFileUpdated);
@ -301,7 +301,7 @@ export default defineComponent({
}
}).then(({ canceled, result: url }) => {
if (canceled) return;
os.api('drive/files/upload_from_url', {
os.api('drive/files/upload-from-url', {
url: url,
folderId: this.folder ? this.folder.id : undefined
});

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" :manual-showing="manualShowing" :src="src" @click="$refs.modal.close()" @opening="opening" @close="$emit('close')" @closed="$emit('closed')">
<MkModal ref="modal" :manual-showing="manualShowing" :src="src" :front="true" @click="$refs.modal.close()" @opening="opening" @close="$emit('close')" @closed="$emit('closed')">
<MkEmojiPicker :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" @chosen="chosen" ref="picker"/>
</MkModal>
</template>

View File

@ -1,7 +1,5 @@
<template>
<div class="xfbouadm" v-if="meta" :style="{ backgroundImage: `url(${ meta.backgroundImageUrl })` }">
</div>
<div class="xfbouadm" v-if="meta" :style="{ backgroundImage: `url(${ meta.backgroundImageUrl })` }"></div>
</template>
<script lang="ts">

View File

@ -71,7 +71,7 @@ export default defineComponent({
},
mounted() {
this.connection = os.stream.useSharedConnection('main');
this.connection = os.stream.useChannel('main');
this.connection.on('follow', this.onFollowChange);
this.connection.on('unfollow', this.onFollowChange);

View File

@ -87,8 +87,6 @@ export default defineComponent({
> .icon {
padding-left: 2px;
font-size: .9em;
font-weight: 400;
font-style: normal;
}
}
</style>

View File

@ -0,0 +1,238 @@
<template>
<MkModal ref="modal" @click="done(true)" @closed="$emit('closed')">
<div class="container">
<div class="fullwidth top-caption">
<div class="mk-dialog">
<header v-if="title"><Mfm :text="title"/></header>
<textarea autofocus v-model="inputValue" :placeholder="input.placeholder" @keydown="onInputKeydown"></textarea>
<div class="buttons" v-if="(showOkButton || showCancelButton)">
<MkButton inline @click="ok" primary>{{ $ts.ok }}</MkButton>
<MkButton inline @click="cancel" >{{ $ts.cancel }}</MkButton>
</div>
</div>
</div>
<div class="hdrwpsaf fullwidth">
<header>{{ image.name }}</header>
<img :src="image.url" :alt="image.comment" :title="image.comment" @click="$refs.modal.close()"/>
<footer>
<span>{{ image.type }}</span>
<span>{{ bytes(image.size) }}</span>
<span v-if="image.properties && image.properties.width">{{ number(image.properties.width) }}px × {{ number(image.properties.height) }}px</span>
</footer>
</div>
</div>
</MkModal>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import MkModal from '@client/components/ui/modal.vue';
import MkButton from '@client/components/ui/button.vue';
import bytes from '@client/filters/bytes';
import number from '@client/filters/number';
export default defineComponent({
components: {
MkModal,
MkButton,
},
props: {
image: {
type: Object,
required: true,
},
title: {
type: String,
required: false
},
input: {
required: true
},
showOkButton: {
type: Boolean,
default: true
},
showCancelButton: {
type: Boolean,
default: true
},
cancelableByBgClick: {
type: Boolean,
default: true
},
},
emits: ['done', 'closed'],
data() {
return {
inputValue: this.input.default ? this.input.default : null
};
},
mounted() {
document.addEventListener('keydown', this.onKeydown);
},
beforeUnmount() {
document.removeEventListener('keydown', this.onKeydown);
},
methods: {
bytes,
number,
done(canceled, result?) {
this.$emit('done', { canceled, result });
this.$refs.modal.close();
},
async ok() {
if (!this.showOkButton) return;
const result = this.inputValue;
this.done(false, result);
},
cancel() {
this.done(true);
},
onBgClick() {
if (this.cancelableByBgClick) {
this.cancel();
}
},
onKeydown(e) {
if (e.which === 27) { // ESC
this.cancel();
}
},
onInputKeydown(e) {
if (e.which === 13) { // Enter
if (e.ctrlKey) {
e.preventDefault();
e.stopPropagation();
this.ok();
}
}
}
}
});
</script>
<style lang="scss" scoped>
.container {
display: flex;
width: 100%;
height: 100%;
flex-direction: row;
}
@media (max-width: 850px) {
.container {
flex-direction: column;
}
.top-caption {
padding-bottom: 8px;
}
}
.fullwidth {
width: 100%;
margin: auto;
}
.mk-dialog {
position: relative;
padding: 32px;
min-width: 320px;
max-width: 480px;
box-sizing: border-box;
text-align: center;
background: var(--panel);
border-radius: var(--radius);
margin: auto;
> header {
margin: 0 0 8px 0;
font-weight: bold;
font-size: 20px;
}
> .buttons {
margin-top: 16px;
> * {
margin: 0 8px;
}
}
> textarea {
display: block;
box-sizing: border-box;
padding: 0 24px;
margin: 0;
width: 100%;
font-size: 16px;
border: none;
border-radius: 0;
background: transparent;
color: var(--fg);
font-family: inherit;
max-width: 100%;
min-width: 100%;
min-height: 90px;
&:focus {
outline: none;
}
&:disabled {
opacity: 0.5;
}
}
}
.hdrwpsaf {
display: flex;
flex-direction: column;
height: 100%;
> header,
> footer {
align-self: center;
display: inline-block;
padding: 6px 9px;
font-size: 90%;
background: rgba(0, 0, 0, 0.5);
border-radius: 6px;
color: #fff;
}
> header {
margin-bottom: 8px;
opacity: 0.9;
}
> img {
display: block;
flex: 1;
min-height: 0;
object-fit: contain;
width: 100%;
cursor: zoom-out;
image-orientation: from-image;
}
> footer {
margin-top: 8px;
opacity: 0.8;
> span + span {
margin-left: 0.5em;
padding-left: 0.5em;
border-left: solid 1px rgba(255, 255, 255, 0.5);
}
}
}
</style>

View File

@ -109,7 +109,7 @@ export default defineComponent({
this.readObserver.observe(this.$el);
this.connection = os.stream.useSharedConnection('main');
this.connection = os.stream.useChannel('main');
this.connection.on('readAllNotifications', () => this.readObserver.unobserve(this.$el));
}
},

View File

@ -12,10 +12,10 @@
<XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/>
</XList>
<button class="_buttonPrimary" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<MkButton primary style="margin: var(--margin) auto;" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
<template v-if="moreFetching"><MkLoading inline/></template>
</button>
</MkButton>
</div>
</transition>
</template>
@ -28,12 +28,14 @@ import XList from './date-separated-list.vue';
import XNote from './note.vue';
import { notificationTypes } from '../../types';
import * as os from '@client/os';
import MkButton from '@client/components/ui/button.vue';
export default defineComponent({
components: {
XNotification,
XList,
XNote,
MkButton,
},
mixins: [
@ -87,7 +89,7 @@ export default defineComponent({
},
mounted() {
this.connection = os.stream.useSharedConnection('main');
this.connection = os.stream.useChannel('main');
this.connection.on('notification', this.onNotification);
},

View File

@ -119,6 +119,10 @@ export default defineComponent({
text: this.$ts.describeFile,
icon: 'fas fa-i-cursor',
action: () => { this.describe(file) }
}, {
text: this.$ts.describeFile,
icon: 'fas fa-i-cursor',
action: () => { this.describe(file) }
}, {
text: this.$ts.attachCancel,
icon: 'fas fa-times-circle',

View File

@ -92,33 +92,33 @@ export default defineComponent({
this.query = {
antennaId: this.antenna
};
this.connection = os.stream.connectToChannel('antenna', {
this.connection = os.stream.useChannel('antenna', {
antennaId: this.antenna
});
this.connection.on('note', prepend);
} else if (this.src == 'home') {
endpoint = 'notes/timeline';
this.connection = os.stream.useSharedConnection('homeTimeline');
this.connection = os.stream.useChannel('homeTimeline');
this.connection.on('note', prepend);
this.connection2 = os.stream.useSharedConnection('main');
this.connection2 = os.stream.useChannel('main');
this.connection2.on('follow', onChangeFollowing);
this.connection2.on('unfollow', onChangeFollowing);
} else if (this.src == 'local') {
endpoint = 'notes/local-timeline';
this.connection = os.stream.useSharedConnection('localTimeline');
this.connection = os.stream.useChannel('localTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'social') {
endpoint = 'notes/hybrid-timeline';
this.connection = os.stream.useSharedConnection('hybridTimeline');
this.connection = os.stream.useChannel('hybridTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'global') {
endpoint = 'notes/global-timeline';
this.connection = os.stream.useSharedConnection('globalTimeline');
this.connection = os.stream.useChannel('globalTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'mentions') {
endpoint = 'notes/mentions';
this.connection = os.stream.useSharedConnection('main');
this.connection = os.stream.useChannel('main');
this.connection.on('mention', prepend);
} else if (this.src == 'directs') {
endpoint = 'notes/mentions';
@ -130,14 +130,14 @@ export default defineComponent({
prepend(note);
}
};
this.connection = os.stream.useSharedConnection('main');
this.connection = os.stream.useChannel('main');
this.connection.on('mention', onNote);
} else if (this.src == 'list') {
endpoint = 'notes/user-list-timeline';
this.query = {
listId: this.list
};
this.connection = os.stream.connectToChannel('userList', {
this.connection = os.stream.useChannel('userList', {
listId: this.list
});
this.connection.on('note', prepend);
@ -148,7 +148,7 @@ export default defineComponent({
this.query = {
channelId: this.channel
};
this.connection = os.stream.connectToChannel('channel', {
this.connection = os.stream.useChannel('channel', {
channelId: this.channel
});
this.connection.on('note', prepend);

View File

@ -1,6 +1,6 @@
<template>
<transition :name="$store.state.animation ? popup ? 'modal-popup' : 'modal' : ''" :duration="$store.state.animation ? popup ? 500 : 300 : 0" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered">
<div v-show="manualShowing != null ? manualShowing : showing" class="mk-modal" v-hotkey.global="keymap" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<div v-show="manualShowing != null ? manualShowing : showing" class="qzhlnise" :class="{ front }" v-hotkey.global="keymap" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<div class="bg _modalBg" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
<div class="content" :class="{ popup, fixed, top: position === 'top' }" @click.self="onBgClick" ref="content">
<slot></slot>
@ -41,6 +41,11 @@ export default defineComponent({
},
position: {
required: false
},
front: {
type: Boolean,
required: false,
default: false,
}
},
emits: ['opening', 'click', 'esc', 'close', 'closed'],
@ -224,14 +229,14 @@ export default defineComponent({
}
}
.mk-modal {
.qzhlnise {
> .bg {
z-index: 20000;
z-index: 10000;
}
> .content:not(.popup) {
position: fixed;
z-index: 20000;
z-index: 10000;
top: 0;
bottom: 0;
left: 0;
@ -263,11 +268,25 @@ export default defineComponent({
> .content.popup {
position: absolute;
z-index: 20000;
z-index: 10000;
&.fixed {
position: fixed;
}
}
&.front {
> .bg {
z-index: 20000;
}
> .content:not(.popup) {
z-index: 20000;
}
> .content.popup {
z-index: 20000;
}
}
}
</style>

View File

@ -163,8 +163,6 @@ fetchInstance().then(() => {
initializeSw();
});
stream.init($i);
const app = createApp(await (
window.location.search === '?zen' ? import('@client/ui/zen.vue') :
!$i ? import('@client/ui/visitor.vue') :
@ -296,7 +294,7 @@ if ($i) {
}
}
const main = stream.useSharedConnection('main', 'System');
const main = stream.useChannel('main', null, 'System');
// 自分の情報が更新されたとき
main.on('meUpdated', i => {
@ -358,10 +356,6 @@ if ($i) {
sound.play('channel');
});
main.on('readAllAnnouncements', () => {
updateAccount({ hasUnreadAnnouncement: false });
});
// トークンが再生成されたとき
// このままではMisskeyが利用できないので強制的にサインアウトさせる
main.on('myTokenRegenerated', () => {

View File

@ -1,26 +1,14 @@
import { computed, reactive } from 'vue';
import * as Misskey from 'misskey-js';
import { api } from './os';
// TODO: 他のタブと永続化されたstateを同期
export type Instance = {
emojis: {
category: string;
}[];
ads: {
id: string;
ratio: number;
place: string;
url: string;
imageUrl: string;
}[];
};
const data = localStorage.getItem('instance');
// TODO: instanceをリアクティブにするかは再考の余地あり
export const instance: Instance = reactive(data ? JSON.parse(data) : {
export const instance: Misskey.entities.InstanceMetadata = reactive(data ? JSON.parse(data) : {
// TODO: set default values
});

View File

@ -3,16 +3,16 @@
import { Component, defineAsyncComponent, markRaw, reactive, Ref, ref } from 'vue';
import { EventEmitter } from 'eventemitter3';
import insertTextAtCursor from 'insert-text-at-cursor';
import * as Misskey from 'misskey-js';
import * as Sentry from '@sentry/browser';
import Stream from '@client/scripts/stream';
import { apiUrl, debug } from '@client/config';
import { apiUrl, debug, url } from '@client/config';
import MkPostFormDialog from '@client/components/post-form-dialog.vue';
import MkWaitingDialog from '@client/components/waiting-dialog.vue';
import { resolve } from '@client/router';
import { $i } from '@client/account';
import { defaultStore } from '@client/store';
export const stream = markRaw(new Stream());
export const stream = markRaw(new Misskey.Stream(url, $i));
export const pendingApiRequestsCount = ref(0);
let apiRequestsCount = 0; // for debug
@ -20,7 +20,11 @@ export const apiRequests = ref([]); // for debug
export const windows = new Map();
export function api(endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) {
const apiClient = new Misskey.api.APIClient({
origin: url,
});
export const api = ((endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) => {
pendingApiRequestsCount.value++;
const onFinally = () => {
@ -56,7 +60,7 @@ export function api(endpoint: string, data: Record<string, any> = {}, token?: st
if (res.status === 200) {
resolve(body);
if (debug) {
log!.res = markRaw(body);
log!.res = markRaw(JSON.parse(JSON.stringify(body)));
log!.state = 'success';
}
} else if (res.status === 204) {
@ -90,17 +94,15 @@ export function api(endpoint: string, data: Record<string, any> = {}, token?: st
promise.then(onFinally, onFinally);
return promise;
}
}) as typeof apiClient.request;
export function apiWithDialog(
export const apiWithDialog = ((
endpoint: string,
data: Record<string, any> = {},
token?: string | null | undefined,
onSuccess?: (res: any) => void,
onFailure?: (e: Error) => void,
) {
) => {
const promise = api(endpoint, data, token);
promiseDialog(promise, onSuccess, onFailure ? onFailure : (e) => {
promiseDialog(promise, null, (e) => {
dialog({
type: 'error',
text: e.message + '\n' + (e as any).id,
@ -108,7 +110,7 @@ export function apiWithDialog(
});
return promise;
}
}) as typeof api;
export function promiseDialog<T extends Promise<any>>(
promise: T,

View File

@ -90,7 +90,7 @@ export default defineComponent({
stats: null,
serverInfo: null,
connection: null,
queueConnection: os.stream.useSharedConnection('queueStats'),
queueConnection: os.stream.useChannel('queueStats'),
memUsage: 0,
chartCpuMem: null,
chartNet: null,
@ -121,7 +121,7 @@ export default defineComponent({
os.api('admin/server-info', {}).then(res => {
this.serverInfo = res;
this.connection = os.stream.useSharedConnection('serverStats');
this.connection = os.stream.useChannel('serverStats');
this.connection.on('stats', this.onStats);
this.connection.on('statsLog', this.onStatsLog);
this.connection.send('requestLog', {

View File

@ -92,6 +92,7 @@ export default defineComponent({
version,
url,
stats: null,
meta: null,
fetchStats: () => os.api('stats', {}),
fetchServerInfo: () => os.api('admin/server-info', {}),
fetchJobs: () => os.api('admin/queue/deliver-delayed', {}),

View File

@ -35,7 +35,7 @@ export default defineComponent({
title: this.$ts.jobQueue,
icon: 'fas fa-clipboard-list',
},
connection: os.stream.useSharedConnection('queueStats'),
connection: os.stream.useChannel('queueStats'),
}
},

View File

@ -19,6 +19,11 @@
<span>{{ $ts.bannerUrl }}</span>
</FormInput>
<FormInput v-model:value="backgroundImageUrl">
<template #prefix><i class="fas fa-link"></i></template>
<span>{{ $ts.backgroundImageUrl }}</span>
</FormInput>
<FormInput v-model:value="tosUrl">
<template #prefix><i class="fas fa-link"></i></template>
<span>{{ $ts.tosUrl }}</span>
@ -88,6 +93,7 @@ export default defineComponent({
maintainerEmail: null,
iconUrl: null,
bannerUrl: null,
backgroundImageUrl: null,
maxNoteTextLength: 0,
enableLocalTimeline: false,
enableGlobalTimeline: false,
@ -106,6 +112,7 @@ export default defineComponent({
this.tosUrl = meta.tosUrl;
this.iconUrl = meta.iconUrl;
this.bannerUrl = meta.bannerUrl;
this.backgroundImageUrl = meta.backgroundImageUrl;
this.maintainerName = meta.maintainerName;
this.maintainerEmail = meta.maintainerEmail;
this.maxNoteTextLength = meta.maxNoteTextLength;
@ -120,6 +127,7 @@ export default defineComponent({
tosUrl: this.tosUrl,
iconUrl: this.iconUrl,
bannerUrl: this.bannerUrl,
backgroundImageUrl: this.backgroundImageUrl,
maintainerName: this.maintainerName,
maintainerEmail: this.maintainerEmail,
maxNoteTextLength: this.maxNoteTextLength,

View File

@ -63,7 +63,7 @@ export default defineComponent({
},
mounted() {
this.connection = os.stream.useSharedConnection('messagingIndex');
this.connection = os.stream.useChannel('messagingIndex');
this.connection.on('message', this.onMessage);
this.connection.on('read', this.onRead);

View File

@ -141,7 +141,7 @@ const Component = defineComponent({
this.group = group;
}
this.connection = os.stream.connectToChannel('messaging', {
this.connection = os.stream.useChannel('messaging', {
otherparty: this.user ? this.user.id : undefined,
group: this.group ? this.group.id : undefined,
});

View File

@ -350,6 +350,9 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
@use "sass:math";
.xqnhankfuuilcwvhgsopeqncafzsquya {
text-align: center;
@ -388,11 +391,11 @@ export default defineComponent({
font-size: 0.8em;
&:first-child {
margin-left: -($gap / 2);
margin-left: -(math.div($gap, 2));
}
&:last-child {
margin-right: -($gap / 2);
margin-right: -(math.div($gap, 2));
}
}
}
@ -413,11 +416,11 @@ export default defineComponent({
font-size: 12px;
&:first-child {
margin-top: -($gap / 2);
margin-top: -(math.div($gap, 2));
}
&:last-child {
margin-bottom: -($gap / 2);
margin-bottom: -(math.div($gap, 2));
}
}
}

View File

@ -61,7 +61,7 @@ export default defineComponent({
if (this.connection) {
this.connection.dispose();
}
this.connection = os.stream.connectToChannel('gamesReversiGame', {
this.connection = os.stream.useChannel('gamesReversiGame', {
gameId: this.game.id
});
this.connection.on('started', this.onStarted);

View File

@ -92,7 +92,7 @@ export default defineComponent({
mounted() {
if (this.$i) {
this.connection = os.stream.useSharedConnection('gamesReversi');
this.connection = os.stream.useChannel('gamesReversi');
this.connection.on('invited', this.onInvited);

View File

@ -220,6 +220,9 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
@use "sass:math";
.uawsfosz {
> div {
padding: 24px;
@ -227,12 +230,12 @@ export default defineComponent({
> .meter {
$size: 12px;
background: rgba(0, 0, 0, 0.1);
border-radius: ($size / 2);
border-radius: math.div($size, 2);
overflow: hidden;
> div {
height: $size;
border-radius: ($size / 2);
border-radius: math.div($size, 2);
}
}
}

View File

@ -4,8 +4,8 @@
<div class="_formLabel"><i class="fab fa-twitter"></i> Twitter</div>
<div class="_formPanel" style="padding: 16px;">
<p v-if="integrations.twitter">{{ $ts.connectedTo }}: <a :href="`https://twitter.com/${integrations.twitter.screenName}`" rel="nofollow noopener" target="_blank">@{{ integrations.twitter.screenName }}</a></p>
<MkButton v-if="integrations.twitter" @click="disconnectTwitter" danger>{{ $ts.disconnectSerice }}</MkButton>
<MkButton v-else @click="connectTwitter" primary>{{ $ts.connectSerice }}</MkButton>
<MkButton v-if="integrations.twitter" @click="disconnectTwitter" danger>{{ $ts.disconnectService }}</MkButton>
<MkButton v-else @click="connectTwitter" primary>{{ $ts.connectService }}</MkButton>
</div>
</div>
@ -13,8 +13,8 @@
<div class="_formLabel"><i class="fab fa-discord"></i> Discord</div>
<div class="_formPanel" style="padding: 16px;">
<p v-if="integrations.discord">{{ $ts.connectedTo }}: <a :href="`https://discord.com/users/${integrations.discord.id}`" rel="nofollow noopener" target="_blank">@{{ integrations.discord.username }}#{{ integrations.discord.discriminator }}</a></p>
<MkButton v-if="integrations.discord" @click="disconnectDiscord" danger>{{ $ts.disconnectSerice }}</MkButton>
<MkButton v-else @click="connectDiscord" primary>{{ $ts.connectSerice }}</MkButton>
<MkButton v-if="integrations.discord" @click="disconnectDiscord" danger>{{ $ts.disconnectService }}</MkButton>
<MkButton v-else @click="connectDiscord" primary>{{ $ts.connectService }}</MkButton>
</div>
</div>
@ -22,8 +22,8 @@
<div class="_formLabel"><i class="fab fa-github"></i> GitHub</div>
<div class="_formPanel" style="padding: 16px;">
<p v-if="integrations.github">{{ $ts.connectedTo }}: <a :href="`https://github.com/${integrations.github.login}`" rel="nofollow noopener" target="_blank">@{{ integrations.github.login }}</a></p>
<MkButton v-if="integrations.github" @click="disconnectGithub" danger>{{ $ts.disconnectSerice }}</MkButton>
<MkButton v-else @click="connectGithub" primary>{{ $ts.connectSerice }}</MkButton>
<MkButton v-if="integrations.github" @click="disconnectGithub" danger>{{ $ts.disconnectService }}</MkButton>
<MkButton v-else @click="connectGithub" primary>{{ $ts.connectService }}</MkButton>
</div>
</div>
</FormBase>

View File

@ -3,6 +3,11 @@ import * as url from '../../prelude/url';
export function getStaticImageUrl(baseUrl: string): string {
const u = new URL(baseUrl);
if (u.href.startsWith(`${instanceUrl}/proxy/`)) {
// もう既にproxyっぽそうだったらsearchParams付けるだけ
u.searchParams.set('static', '1');
return u.href;
}
const dummy = `${u.host}${u.pathname}`; // 拡張子がないとキャッシュしてくれないCDNがあるので
return `${instanceUrl}/proxy/${dummy}?${url.query({
url: u.href,

View File

@ -47,7 +47,7 @@ export function selectFile(src: any, label: string | null, multiple = false) {
const marker = Math.random().toString(); // TODO: UUIDとか使う
const connection = os.stream.useSharedConnection('main');
const connection = os.stream.useChannel('main');
connection.on('urlUploadFinished', data => {
if (data.marker === marker) {
res(multiple ? [data.file] : data.file);
@ -55,7 +55,7 @@ export function selectFile(src: any, label: string | null, multiple = false) {
}
});
os.api('drive/files/upload_from_url', {
os.api('drive/files/upload-from-url', {
url: url,
marker
});

View File

@ -1,312 +0,0 @@
import autobind from 'autobind-decorator';
import { EventEmitter } from 'eventemitter3';
import ReconnectingWebsocket from 'reconnecting-websocket';
import { markRaw } from 'vue';
import { debug, wsUrl } from '@client/config';
import { query as urlQuery } from '../../prelude/url';
/**
* Misskey stream connection
*/
export default class Stream extends EventEmitter {
private stream: ReconnectingWebsocket;
public state: 'initializing' | 'reconnecting' | 'connected' = 'initializing';
private sharedConnectionPools: Pool[] = [];
private sharedConnections: SharedConnection[] = [];
private nonSharedConnections: NonSharedConnection[] = [];
@autobind
public init(user): void {
const query = urlQuery({
i: user?.token,
_t: Date.now(),
});
this.stream = new ReconnectingWebsocket(`${wsUrl}?${query}`, '', { minReconnectionDelay: 1 }); // https://github.com/pladaria/reconnecting-websocket/issues/91
this.stream.addEventListener('open', this.onOpen);
this.stream.addEventListener('close', this.onClose);
this.stream.addEventListener('message', this.onMessage);
}
@autobind
public useSharedConnection(channel: string, name?: string): SharedConnection {
let pool = this.sharedConnectionPools.find(p => p.channel === channel);
if (pool == null) {
pool = new Pool(this, channel);
this.sharedConnectionPools.push(pool);
}
const connection = markRaw(new SharedConnection(this, channel, pool, name));
this.sharedConnections.push(connection);
return connection;
}
@autobind
public removeSharedConnection(connection: SharedConnection) {
this.sharedConnections = this.sharedConnections.filter(c => c !== connection);
}
@autobind
public removeSharedConnectionPool(pool: Pool) {
this.sharedConnectionPools = this.sharedConnectionPools.filter(p => p !== pool);
}
@autobind
public connectToChannel(channel: string, params?: any): NonSharedConnection {
const connection = markRaw(new NonSharedConnection(this, channel, params));
this.nonSharedConnections.push(connection);
return connection;
}
@autobind
public disconnectToChannel(connection: NonSharedConnection) {
this.nonSharedConnections = this.nonSharedConnections.filter(c => c !== connection);
}
/**
* Callback of when open connection
*/
@autobind
private onOpen() {
const isReconnect = this.state === 'reconnecting';
this.state = 'connected';
this.emit('_connected_');
// チャンネル再接続
if (isReconnect) {
for (const p of this.sharedConnectionPools)
p.connect();
for (const c of this.nonSharedConnections)
c.connect();
}
}
/**
* Callback of when close connection
*/
@autobind
private onClose() {
if (this.state === 'connected') {
this.state = 'reconnecting';
this.emit('_disconnected_');
}
}
/**
* Callback of when received a message from connection
*/
@autobind
private onMessage(message) {
const { type, body } = JSON.parse(message.data);
if (type === 'channel') {
const id = body.id;
let connections: Connection[];
connections = this.sharedConnections.filter(c => c.id === id);
if (connections.length === 0) {
connections = [this.nonSharedConnections.find(c => c.id === id)];
}
for (const c of connections.filter(c => c != null)) {
c.emit(body.type, Object.freeze(body.body));
if (debug) c.inCount++;
}
} else {
this.emit(type, Object.freeze(body));
}
}
/**
* Send a message to connection
*/
@autobind
public send(typeOrPayload, payload?) {
const data = payload === undefined ? typeOrPayload : {
type: typeOrPayload,
body: payload
};
this.stream.send(JSON.stringify(data));
}
/**
* Close this connection
*/
@autobind
public close() {
this.stream.removeEventListener('open', this.onOpen);
this.stream.removeEventListener('message', this.onMessage);
}
}
let idCounter = 0;
class Pool {
public channel: string;
public id: string;
protected stream: Stream;
public users = 0;
private disposeTimerId: any;
private isConnected = false;
constructor(stream: Stream, channel: string) {
this.channel = channel;
this.stream = stream;
this.id = (++idCounter).toString();
this.stream.on('_disconnected_', this.onStreamDisconnected);
}
@autobind
private onStreamDisconnected() {
this.isConnected = false;
}
@autobind
public inc() {
if (this.users === 0 && !this.isConnected) {
this.connect();
}
this.users++;
// タイマー解除
if (this.disposeTimerId) {
clearTimeout(this.disposeTimerId);
this.disposeTimerId = null;
}
}
@autobind
public dec() {
this.users--;
// そのコネクションの利用者が誰もいなくなったら
if (this.users === 0) {
// また直ぐに再利用される可能性があるので、一定時間待ち、
// 新たな利用者が現れなければコネクションを切断する
this.disposeTimerId = setTimeout(() => {
this.disconnect();
}, 3000);
}
}
@autobind
public connect() {
if (this.isConnected) return;
this.isConnected = true;
this.stream.send('connect', {
channel: this.channel,
id: this.id
});
}
@autobind
private disconnect() {
this.stream.off('_disconnected_', this.onStreamDisconnected);
this.stream.send('disconnect', { id: this.id });
this.stream.removeSharedConnectionPool(this);
}
}
abstract class Connection extends EventEmitter {
public channel: string;
protected stream: Stream;
public abstract id: string;
public name?: string; // for debug
public inCount: number = 0; // for debug
public outCount: number = 0; // for debug
constructor(stream: Stream, channel: string, name?: string) {
super();
this.stream = stream;
this.channel = channel;
this.name = name;
}
@autobind
public send(id: string, typeOrPayload, payload?) {
const type = payload === undefined ? typeOrPayload.type : typeOrPayload;
const body = payload === undefined ? typeOrPayload.body : payload;
this.stream.send('ch', {
id: id,
type: type,
body: body
});
if (debug) this.outCount++;
}
public abstract dispose(): void;
}
class SharedConnection extends Connection {
private pool: Pool;
public get id(): string {
return this.pool.id;
}
constructor(stream: Stream, channel: string, pool: Pool, name?: string) {
super(stream, channel, name);
this.pool = pool;
this.pool.inc();
}
@autobind
public send(typeOrPayload, payload?) {
super.send(this.pool.id, typeOrPayload, payload);
}
@autobind
public dispose() {
this.pool.dec();
this.removeAllListeners();
this.stream.removeSharedConnection(this);
}
}
class NonSharedConnection extends Connection {
public id: string;
protected params: any;
constructor(stream: Stream, channel: string, params?: any) {
super(stream, channel);
this.params = params;
this.id = (++idCounter).toString();
this.connect();
}
@autobind
public connect() {
this.stream.send('connect', {
channel: this.channel,
id: this.id,
params: this.params
});
}
@autobind
public send(typeOrPayload, payload?) {
super.send(this.id, typeOrPayload, payload);
}
@autobind
public dispose() {
this.removeAllListeners();
this.stream.send('disconnect', { id: this.id });
this.stream.disconnectToChannel(this);
}
}

View File

@ -146,6 +146,7 @@ hr {
width: 100%;
height: 100%;
background: var(--modalBg);
-webkit-backdrop-filter: var(--modalBgFilter);
backdrop-filter: var(--modalBgFilter);
}

View File

@ -43,7 +43,7 @@ export default defineComponent({
};
if ($i) {
const connection = stream.useSharedConnection('main', 'UI');
const connection = stream.useChannel('main', null, 'UI');
connection.on('notification', onNotification);
}

View File

@ -121,33 +121,33 @@ export default defineComponent({
this.query = {
antennaId: this.antenna
};
this.connection = os.stream.connectToChannel('antenna', {
this.connection = os.stream.useChannel('antenna', {
antennaId: this.antenna
});
this.connection.on('note', prepend);
} else if (this.src == 'home') {
endpoint = 'notes/timeline';
this.connection = os.stream.useSharedConnection('homeTimeline');
this.connection = os.stream.useChannel('homeTimeline');
this.connection.on('note', prepend);
this.connection2 = os.stream.useSharedConnection('main');
this.connection2 = os.stream.useChannel('main');
this.connection2.on('follow', onChangeFollowing);
this.connection2.on('unfollow', onChangeFollowing);
} else if (this.src == 'local') {
endpoint = 'notes/local-timeline';
this.connection = os.stream.useSharedConnection('localTimeline');
this.connection = os.stream.useChannel('localTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'social') {
endpoint = 'notes/hybrid-timeline';
this.connection = os.stream.useSharedConnection('hybridTimeline');
this.connection = os.stream.useChannel('hybridTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'global') {
endpoint = 'notes/global-timeline';
this.connection = os.stream.useSharedConnection('globalTimeline');
this.connection = os.stream.useChannel('globalTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'mentions') {
endpoint = 'notes/mentions';
this.connection = os.stream.useSharedConnection('main');
this.connection = os.stream.useChannel('main');
this.connection.on('mention', prepend);
} else if (this.src == 'directs') {
endpoint = 'notes/mentions';
@ -159,14 +159,14 @@ export default defineComponent({
prepend(note);
}
};
this.connection = os.stream.useSharedConnection('main');
this.connection = os.stream.useChannel('main');
this.connection.on('mention', onNote);
} else if (this.src == 'list') {
endpoint = 'notes/user-list-timeline';
this.query = {
listId: this.list
};
this.connection = os.stream.connectToChannel('userList', {
this.connection = os.stream.useChannel('userList', {
listId: this.list
});
this.connection.on('note', prepend);
@ -178,7 +178,7 @@ export default defineComponent({
this.query = {
channelId: this.channel
};
this.connection = os.stream.connectToChannel('channel', {
this.connection = os.stream.useChannel('channel', {
channelId: this.channel
});
this.connection.on('note', prepend);

View File

@ -241,7 +241,6 @@ export default defineComponent({
> .text {
display: none;
}
}
}
@ -309,7 +308,7 @@ export default defineComponent({
> .indicator {
position: absolute;
top: 0;
left: 20px;
left: 0;
color: var(--navIndicator);
font-size: 8px;
animation: blink 1s infinite;

View File

@ -65,7 +65,7 @@ export default defineComponent({
extends: widget,
data() {
return {
connection: os.stream.useSharedConnection('queueStats'),
connection: os.stream.useChannel('queueStats'),
inbox: {
activeSincePrevTick: 0,
active: 0,

View File

@ -48,7 +48,7 @@ export default defineComponent({
};
},
mounted() {
this.connection = os.stream.useSharedConnection('main');
this.connection = os.stream.useChannel('main');
this.connection.on('driveFileCreated', this.onDriveFileCreated);

View File

@ -63,7 +63,7 @@ export default defineComponent({
os.api('server-info', {}).then(res => {
this.meta = res;
});
this.connection = os.stream.useSharedConnection('serverStats');
this.connection = os.stream.useChannel('serverStats');
},
unmounted() {
this.connection.dispose();

View File

@ -1,25 +1,25 @@
# ストリーミングAPI
# API de Streaming
ストリーミングAPIを使うと、リアルタイムで様々な情報(例えばタイムラインに新しい投稿が流れてきた、メッセージが届いた、フォローされた、など)を受け取ったり、様々な操作を行ったりすることができます。
Usando la API de streaming, se puede recibir en tiempo real toda clase de información (por ejemplo, los posts nuevos que pasaron por la linea de tiempo, los mensajes recibidos, las notificaciones de seguimiento, etc.) y manejar varias operaciones en estas.
## ストリームに接続する
## Conectarse a streams
ストリーミングAPIを利用するには、まずMisskeyサーバーに**websocket**接続する必要があります。
Para usar la API de streaming, primero hay que conectar un **websocket** al servidor de Misskey
以下のURLに、`i`というパラメータ名で認証情報を含めて、websocket接続してください。例:
Conecte el websocket a la URL mencionada abajo, incluyendo la información de autenticación en el parámetro `i`Ej:
```
%WS_URL%/streaming?i=xxxxxxxxxxxxxxx
```
認証情報は、自分のAPIキーや、アプリケーションからストリームに接続する際はユーザーのアクセストークンのことを指します。
La información de autenticación hace referencia a tu propia clave de la API, o al token de acceso del usuario cuando se conecta al stream desde la aplicación
<div class="ui info">
<p><i class="fas fa-info-circle"></i> 認証情報の取得については、<a href="./api">こちらのドキュメント</a>をご確認ください。</p>
<p><i class="fas fa-info-circle"></i> Para obtener la información de la autenticación, consulte <a href="./api">Este documento</a></p>
</div>
---
認証情報は省略することもできますが、その場合非ログインでの利用ということになり、受信できる情報や可能な操作は限られます。例:
La información de autenticación puede omitirse, pero en ese caso de uso sin un login, se restringirá la información que puede ser recibida y las operaciones posibles,Ej:
```
%WS_URL%/streaming
@ -50,7 +50,7 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
Aquí
* `channel`には接続したいチャンネル名を設定します。チャンネルの種類については後述します。
* `id`にはそのチャンネルとやり取りするための任意のIDを設定します。ストリームでは様々なメッセージが流れるので、そのメッセージがどのチャンネルからのものなのか識別する必要があるからです。このIDは、UUIDや、乱数のようなもので構いません。
* `params`はチャンネルに接続する際のパラメータです。チャンネルによって接続時に必要とされるパラメータは異なります。パラメータ不要のチャンネルに接続する際は、このプロパティは省略可能です。
@ -76,7 +76,7 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
Aquí
* `id`には前述したそのチャンネルに接続する際に設定したIDが設定されています。これで、このメッセージがどのチャンネルからのものなのか知ることができます。
* `type`にはメッセージの種類が設定されます。チャンネルによって、どのような種類のメッセージが流れてくるかは異なります。
* `body`にはメッセージの内容が設定されます。チャンネルによって、どのような内容のメッセージが流れてくるかは異なります。
@ -98,7 +98,7 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
Aquí
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。これで、このメッセージがどのチャンネルに向けたものなのか識別させることができます。
* `type`にはメッセージの種類を設定します。チャンネルによって、どのような種類のメッセージを受け付けるかは異なります。
* `body`にはメッセージの内容を設定します。チャンネルによって、どのような内容のメッセージを受け付けるかは異なります。
@ -115,7 +115,7 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
Aquí
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。
## ストリームを経由してAPIリクエストする
@ -136,7 +136,7 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
Aquí
* `id`には、APIのレスポンスを識別するための、APIリクエストごとの一意なIDを設定する必要があります。UUIDや、簡単な乱数のようなもので構いません。
* `endpoint`には、あなたがリクエストしたいAPIのエンドポイントを指定します。
* `data`には、エンドポイントのパラメータを含めます。
@ -158,7 +158,7 @@ APIへリクエストすると、レスポンスがストリームから次の
}
```
ここで、
Aquí
* `xxxxxxxxxxxxxxxx`の部分には、リクエストの際に設定された`id`が含まれています。これにより、どのリクエストに対するレスポンスなのか判別することができます。
* `body`には、レスポンスが含まれています。
@ -185,7 +185,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
}
```
ここで、
Aquí
* `id`にキャプチャしたい投稿の`id`を設定します。
このメッセージを送信すると、Misskeyにキャプチャを要請したことになり、以後、その投稿に関するイベントが流れてくるようになります。
@ -206,7 +206,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
}
```
ここで、
Aquí
* `body`内の`id`に、イベントを発生させた投稿のIDが設定されます。
* `body`内の`type`に、イベントの種類が設定されます。
* `body`内の`body`に、イベントの詳細が設定されます。
@ -219,7 +219,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
* `reaction`に、リアクションの種類が設定されます。
* `userId`に、リアクションを行ったユーザーのIDが設定されます。
:
Ej:
```json
{
type: 'noteUpdated',
@ -239,7 +239,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
* `deletedAt`に、削除日時が設定されます。
:
Ej:
```json
{
type: 'noteUpdated',
@ -259,7 +259,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
* `choice`に、選択肢IDが設定されます。
* `userId`に、投票を行ったユーザーのIDが設定されます。
:
Ej:
```json
{
type: 'noteUpdated',
@ -289,7 +289,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
}
```
ここで、
Aquí
* `id`にキャプチャを解除したい投稿の`id`を設定します。
このメッセージを送信すると、以後、その投稿に関するイベントは流れてこないようになります。

View File

@ -1,12 +1,12 @@
# Tema
テーマを設定して、Misskeyクライアントの見た目を変更できます。
Eligiendo un tema, se puede cambiar la apariencia del cliente de Misskey
## テーマの設定
設定 > テーマ
## Configuración del tema
Configuración > Tema
## テーマを作成する
テーマコードはJSON5で記述されたテーマオブジェクトです。 テーマは以下のようなオブジェクトです。
## Crear tema
El código del tema se guarda como un archivo JSON5. Un ejemplo de tema se puede ver aquí:
``` js
{
id: '17587283-dd92-4a2c-a22c-be0637c9e22a',
@ -33,36 +33,36 @@
```
* `id` ... テーマの一意なID。UUIDをおすすめします。
* `name` ... テーマ名
* `author` ... テーマの作者
* `desc` ... テーマの説明(オプション)
* `base` ... 明るいテーマか、暗いテーマか
* `light`にすると明るいテーマになり、`dark`にすると暗いテーマになります。
* テーマはここで設定されたベーステーマを継承します。
* `props` ... テーマのスタイル定義。これから説明します。
* `id` ... Clave única del tema.Se recomienda un código UUID
* `name` ... Nombre del tema
* `author` ... Autor del tema
* `desc` ... Descripción del tema (opcional)
* `base` ... Si es un tema claro u oscuro
* Si se elige `light`, será un tema claro. Si se elige `dark`, será un tema oscuro.
* Aquí el tema hereda los valores por defecto del tema base elegido
* `props` ... Definición del estilo del tema. Esto se explica en lo siguiente.
### テーマのスタイル定義
`props`下にはテーマのスタイルを定義します。 キーがCSSの変数名になり、バリューで中身を指定します。 なお、この`props`オブジェクトはベーステーマから継承されます。 ベーステーマは、このテーマの`base`が`light`なら[_light.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_light.json5)で、`dark`なら[_dark.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_dark.json5)です。 つまり、このテーマ内の`props`に`panel`というキーが無くても、そこにはベーステーマの`panel`があると見なされます。
### Definición del estilo del tema
Debajo de `props`, se define el estilo del tema. La clave es el nombre de las variables del CSS, y con los valores estos se configuran. Incluso más, este objeto `props` hereda los valores por defecto del tema base. El tema base es [_light.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_light.json5) si el `base` de este tema es `light`, y [_dark.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_dark.json5) si si el `base` de este tema es `dark` Resumiendo, aunque no haya una clave `panel` en el `props` del tema, se considera el <0>panel</0> del tema base.
#### バリューで使える構文
* 16進数で表された色
* : `#00ff00`
* `rgb(r, g, b)`形式で表された色
* : `rgb(0, 255, 0)`
* `rgb(r, g, b, a)`形式で表された透明度を含む色
* : `rgba(0, 255, 0, 0.5)`
* 他のキーの値の参照
* `@{キー名}`と書くと他のキーの値の参照になります。`{キー名}`は参照したいキーの名前に置き換えます。
* : `@panel`
* 定数(後述)の参照
* `${定数名}`と書くと定数の参照になります。`{定数名}`は参照したい定数の名前に置き換えます。
* : `$main`
* 関数(後述)
* `:{関数名}<{引数}<{色}`
#### Sintaxis de las variables
* Los colores en base hexadecimal
* Ej: `#00ff00`
* Los colores con la sintaxis `rgb(r, g, b)`
* Ej: `rgb(0, 255, 0)`
* Los colores con la sintaxis `rgb(r, g, b, a)` con un grado de transparencia
* Ej: `rgba(0, 255, 0, 0.5)`
* Referencias a valores de otras claves
* Escribiendo `@{nombre de clave}` se hace referencia al valor de la otra clave.Reemplace `{nombre de clave}` por el nombre de la clave al cual quiera hacer referencia.
* Ej: `@panel`
* Referencia a una constante (ver más abajo)
* Escribiendo `${nombre de la constante}` se hace referencia a la constante.Reemplace `{nombre de la constante}` por la constante al cual quiera hacer referencia.
* Ej: `$main`
* Funciones (ver más abajo)
* `:{nombre de la función}<{parámetros}<{color}`
#### Constante
「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。 キー名を`$`で始めると、そのキーはCSS変数として出力されません。
#### Constantes
Cuando hay un valor que no se quiere generar como variable CSS pero sí se quiere reutilizar como valor de otra variable CSS, es conveniente usar constantes. Cuando a un nombre de clave se le añade como prefijo `$`, esa clave no será generada como una variable CSS.
#### funciones
wip

View File

@ -1,15 +1,15 @@
# タイムラインの比較
# Comparación de las lineas de tiempo
https://docs.google.com/spreadsheets/d/1lxQ2ugKrhz58Bg96HTDK_2F98BUritkMyIiBkOByjHA/edit?usp=sharing
## Inicio
自分のフォローしているユーザーの投稿
Los posts de los usuarios que uno sigue
## Local
全てのローカルユーザーの「ホーム」指定されていない投稿
Todos los posts de los usuarios locales que no estén marcados como "Solo inicio"
## Social
自分のフォローしているユーザーの投稿と、全てのローカルユーザーの「ホーム」指定されていない投稿
Los posts de los usuarios que uno sigue más todos los posts de los usuarios locales que no estén marcados como "Solo inicio"
## Global
全てのローカルユーザーの「ホーム」指定されていない投稿と、サーバーに届いた全てのリモートユーザーの「ホーム」指定されていない投稿
Todos los posts de los usuarios locales que no estén marcados como "Solo inicio" más todos los posts de los usuarios remotos recibidos por el servidor que no estén marcados como "Solo inicio"

View File

@ -1,4 +1,4 @@
# AiScript
## 関数
デフォルトで値渡しです。
## Fungsi
Secara bawaan, berjalan sebagai pass dari value.

View File

@ -1,19 +1,19 @@
# Misskey API
MisskeyAPIを使ってMisskeyクライアント、Misskey連携Webサービス、Bot等(以下「アプリケーション」と呼びます)を開発できます。 ストリーミングAPIもあるので、リアルタイム性のあるアプリケーションを作ることも可能です。
Dengan menggunakan Misskey API kamu dapat mengembangkan klien Misskey, Webservice yang terintegrasi dengan Misskey, Bots (nantinya akan disebut "Aplikasi" disini), dll. Terdapat juga streaming API, yang memungkinan untuk membuat aplikasi real-time.
APIを使い始めるには、まずアクセストークンを取得する必要があります。 このドキュメントでは、アクセストークンを取得する手順を説明した後、基本的なAPIの使い方を説明します。
Untuk memulai menggunakin API, kamu harus memiliki access token terlebih dahulu. Halaman ini akan menjelaskan bagaimana untuk mendapatkan access token dan menjelaskan instruksi penggunaan dasar dari Misskey API.
## アクセストークンの取得
基本的に、APIはリクエストにはアクセストークンが必要となります。 APIにリクエストするのが自分自身なのか、不特定の利用者に使ってもらうアプリケーションなのかによって取得手順は異なります。
## Mendapatkan access token
Pada dasarnya, semua request API membutuhkan access token. Metode untuk mendapatkan sebuah access token bermacam-macam bergantung pada kamu sendiri yang mengirim request API atau request tersebut dikirim melalui aplikasi yang dipakai oleh pengguna akhir.
* 前者の場合: [「自分自身のアクセストークンを手動発行する」](#自分自身のアクセストークンを手動発行する)に進む
* 後者の場合: [「アプリケーション利用者にアクセストークンの発行をリクエストする」](#アプリケーション利用者にアクセストークンの発行をリクエストする)に進む
* Apabila kamu pengguna lama: Langsung saja menuju [ "Menerbitkan access token untuk akun kamu sendiri secara manual" ](#自分自身のアクセストークンを手動発行する)
* Apabila kamu pengguna baru: Langsung saja menuju [ "Meminta aplikasi pengguna untuk menghasilkan access token" ](#アプリケーション利用者にアクセストークンの発行をリクエストする)
### 自分自身のアクセストークンを手動発行する
「設定 > API」で、自分のアクセストークンを発行できます。
### Menerbitkan access token untuk akun kamu sendiri secara manual
Kamu dapat membuat access token untuk akun milikmu di Pengaturan > API.
[「APIの使い方」へ進む](#APIの使い方)
[Lanjutkan untuk menggunakan API.](#APIの使い方)
### アプリケーション利用者にアクセストークンの発行をリクエストする
アプリケーション利用者のアクセストークンを取得するには、以下の手順で発行をリクエストします。
@ -49,7 +49,7 @@ UUIDを生成する。以後これをセッションIDと呼びます。
* `token` ... ユーザーのアクセストークン
* `user` ... ユーザーの情報
[「APIの使い方」へ進む](#APIの使い方)
[Lanjutkan untuk menggunakan API.](#APIの使い方)
## APIの使い方
**APIはすべてPOSTで、リクエスト/レスポンスともにJSON形式です。RESTではありません。** アクセストークンは、`i`というパラメータ名でリクエストに含めます。

View File

@ -1,7 +1,7 @@
# プラグインの作成
Misskey Webクライアントのプラグイン機能を使うと、クライアントを拡張し、様々な機能を追加できます。 ここではプラグインの作成にあたってのメタデータ定義や、AiScript APIリファレンスを掲載します。
## メタデータ
## Metadata
プラグインは、AiScriptのメタデータ埋め込み機能を使って、デフォルトとしてプラグインのメタデータを定義する必要があります。 メタデータは次のプロパティを含むオブジェクトです。
### name

View File

@ -1,2 +1,2 @@
# Emoji kustom
カスタム絵文字は、インスタンスで用意された画像を絵文字のように使える機能です。 ノート、リアクション、チャット、自己紹介、名前などの場所で使うことができます。 カスタム絵文字をそれらの場所で使うには、絵文字ピッカーボタン(ある場合)を押すか、`:`を入力して絵文字サジェストを表示します。 テキスト内に`:foo:`のような形式の文字列が見つかると、`foo`の部分がカスタム絵文字名と解釈され、表示時には対応したカスタム絵文字に置き換わります。
Emoji kustom merupakan fungsi yang menyediakan gambar terunggah ke server untuk digunakan seperti emoji. Emoji kustom ini dapt digunakan pada note, reaksi, obrolan, profil, dan bahkan username serta tempat-tempat lainnya. Untuk menggunakan emoji kustom pada tempat yang disebutkan di atas, tekan tombol pemilih Emoji (bila ada) atau ketik sebuah `:` dan jendela saran emoji akan muncul. Jika sebuah string yang terlihat seperti `:foo:` ditemukan dalam text apapun, maka sebagian dari `foo` diinterpretaskan sebagai nama emoji kustom dan akan digantikan dengan gambar emoji kustom ketika ditampilkan.

View File

@ -1,4 +1,4 @@
# デッキ
# Dek
デッキは利用可能なUIのひとつです。「カラム」と呼ばれるビューを複数並べて表示させることで、カスタマイズ性が高く、情報量の多いUIが構築できることが特徴です。

View File

@ -1,2 +1,2 @@
# Ikuti
ユーザーをフォローすると、タイムラインにそのユーザーの投稿が表示されるようになります。ただし、他のユーザーに対する返信は含まれません。 ユーザーをフォローするには、ユーザーページの「フォロー」ボタンをクリックします。フォローを解除するには、もう一度クリックします。
Jika kamu mengikuti seorang pengguna, postingan dari pengguna tersebut akan muncul pada linimasa kamu.Akan tetapi, balasan dari mereka kepada pengguna lain tidak akan ditampilkan. Untuk mengikuti seorang pengguna, klik tombol "Ikuti" pada halaman pengguna mereka.Untuk berhenti mengikuti seorang pengguna, klik tombol tersebut sekali lagi.

View File

@ -1,6 +1,6 @@
# キーボードショートカット
## グローバル
## Global
これらのショートカットは基本的にどこでも使えます。
<table>
<thead>

View File

@ -1,6 +1,6 @@
# Pages
## 変数
## Variabel
変数を使うことで動的なページを作成できます。テキスト内で <b>{ 変数名 }</b> と書くとそこに変数の値を埋め込めます。例えば <b>Hello { thing } world!</b> というテキストで、変数(thing)の値が <b>ai</b> だった場合、テキストは <b>Hello ai world!</b> になります。
変数の評価(値を算出すること)は上から下に行われるので、ある変数の中で自分より下の変数を参照することはできません。例えば上から <b>A、B、C</b> と3つの変数を定義したとき、<b>C</b>の中で<b>A</b><b>B</b>を参照することはできますが、<b>A</b>の中で<b>B</b><b>C</b>を参照することはできません。

View File

@ -110,7 +110,7 @@ y = Math.floor(pos / mapWidth)
```
### フォームコントロールの種類
#### スイッチ
#### Beralih
type: `switch` スイッチを表示します。何かの機能をオン/オフさせたい場合に有用です。
##### プロパティ

View File

@ -31,7 +31,7 @@
**ストリームでのやり取りはすべてJSONです。**
## チャンネル
## Kanal
MisskeyのストリーミングAPIにはチャンネルという概念があります。これは、送受信する情報を分離するための仕組みです。 Misskeyのストリームに接続しただけでは、まだリアルタイムでタイムラインの投稿を受信したりはできません。 ストリーム上でチャンネルに接続することで、様々な情報を受け取ったり情報を送信したりすることができるようになります。
### チャンネルに接続する

View File

@ -1,4 +1,4 @@
# テーマ
# Tema
テーマを設定して、Misskeyクライアントの見た目を変更できます。
@ -61,8 +61,8 @@
* 関数(後述)
* `:{関数名}<{引数}<{色}`
#### 定数
#### Konstanta
「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。 キー名を`$`で始めると、そのキーはCSS変数として出力されません。
#### 関数
#### Fungsi
wip

View File

@ -1,15 +1,15 @@
# タイムラインの比較
# Perbandingan Linimasa
https://docs.google.com/spreadsheets/d/1lxQ2ugKrhz58Bg96HTDK_2F98BUritkMyIiBkOByjHA/edit?usp=sharing
## ホーム
自分のフォローしているユーザーの投稿
## Beranda
Postingan dari pengguna yang kamu ikuti
## ローカル
全てのローカルユーザーの「ホーム」指定されていない投稿
## Lokal
Seluruh postingan dari pengguna lokal yang tidak ditandai sebagai "Hanya Beranda"
## ソーシャル
自分のフォローしているユーザーの投稿と、全てのローカルユーザーの「ホーム」指定されていない投稿
## Sosial
Postingan dari pengguna yang kamu ikuti beserta dengan semua postingan dari pengguna lokal yang tidak ditandai sebagai "Hanya Beranda"
## グローバル
全てのローカルユーザーの「ホーム」指定されていない投稿と、サーバーに届いた全てのリモートユーザーの「ホーム」指定されていない投稿
## Global
Seluruh postingan dari pengguna lokal yang tidak ditandai sebagai "Hanya Beranda" dan juga pesan yang diterima oleh server yang tidak ditandai sebagai "Hanya Beranda"

View File

@ -7,11 +7,11 @@ API를 사용하려면 먼저 액세스 토큰을 취득해야 합니다. 이
## 액세스 토큰 가져오기
기본적으로 API는 요청 시에 액세스 토큰이 필요합니다. API에 요청하는 것이 자기 자신인지, 불특정한 유저에게 사용하는 애플리케이션인지에 따라 취득 절차가 달라집니다.
* 전자의 경우: [ 「자기 자신의 액세스 토큰을 수동으로 발급하기」](#自分自身のアクセストークンを手動発行する)로 진행
* 전자의 경우: [「자기 자신의 액세스 토큰을 수동으로 발급하기」](#自分自身のアクセストークンを手動発行する)로 진행
* 후자의 경우: [「애플리케이션 사용자에게 액세스 토큰 발급을 요청하기」](#アプリケーション利用者にアクセストークンの発行をリクエストする)로 진행
### 자기 자신의 액세스 토큰을 수동으로 발급하기
「설정 &#062 API」에서 자신의 액세스 토큰을 발급할 수 있습니다.
「설정 > API」에서 자신의 액세스 토큰을 발급할 수 있습니다.
[「API 사용 방법」으로 이동](#APIの使い方)

View File

@ -1,2 +1,2 @@
# MFM
MFM은 Misskey Flavored Markdown의 약자로, Misskey의 다양한 장소에서 사용할 수 있는 전용 마크업 언어입니다. MFM로 사용 가능한 구문은 [MFM 치트 시트 ](/mfm-cheat-sheet)에서 확인할 수 있습니다.
MFM은 Misskey Flavored Markdown의 약자로, Misskey의 다양한 장소에서 사용할 수 있는 전용 마크업 언어입니다. MFM로 사용 가능한 구문은 [MFM 치트 시트](/mfm-cheat-sheet)에서 확인할 수 있습니다.

View File

@ -8,7 +8,7 @@ Wpisy użytkowników, których obserwujesz
## Lokalne
全てのローカルユーザーの「ホーム」指定されていない投稿
## ソーシャル
## Społeczność
自分のフォローしているユーザーの投稿と、全てのローカルユーザーの「ホーム」指定されていない投稿
## Globalne

View File

@ -93,6 +93,9 @@
{ "category": "face", "char": "🥱", "name": "yawning", "keywords": ["face", "tired", "yawning"] },
{ "category": "face", "char": "😴", "name": "sleeping", "keywords": ["face", "tired", "sleepy", "night", "zzz"] },
{ "category": "face", "char": "💤", "name": "zzz", "keywords": ["sleepy", "tired", "dream"] },
{ "category": "face", "char": "\uD83D\uDE36\u200D\uD83C\uDF2B\uFE0F", "name": "face_in_clouds", "keywords": [] },
{ "category": "face", "char": "\uD83D\uDE2E\u200D\uD83D\uDCA8", "name": "face_exhaling", "keywords": [] },
{ "category": "face", "char": "\uD83D\uDE35\u200D\uD83D\uDCAB", "name": "face_with_spiral_eyes", "keywords": [] },
{ "category": "face", "char": "💩", "name": "poop", "keywords": ["hankey", "shitface", "fail", "turd", "shit"] },
{ "category": "face", "char": "😈", "name": "smiling_imp", "keywords": ["devil", "horns"] },
{ "category": "face", "char": "👿", "name": "imp", "keywords": ["devil", "angry", "horns"] },
@ -1219,6 +1222,8 @@
{ "category": "symbols", "char": "💘", "name": "cupid", "keywords": ["love", "like", "heart", "affection", "valentines"] },
{ "category": "symbols", "char": "💝", "name": "gift_heart", "keywords": ["love", "valentines"] },
{ "category": "symbols", "char": "💟", "name": "heart_decoration", "keywords": ["purple-square", "love", "like"] },
{ "category": "symbols", "char": "\u2764\uFE0F\u200D\uD83D\uDD25", "name": "heart_on_fire", "keywords": [] },
{ "category": "symbols", "char": "\u2764\uFE0F\u200D\uD83E\uDE79", "name": "mending_heart", "keywords": [] },
{ "category": "symbols", "char": "☮", "name": "peace_symbol", "keywords": ["hippie"] },
{ "category": "symbols", "char": "✝", "name": "latin_cross", "keywords": ["christianity"] },
{ "category": "symbols", "char": "☪", "name": "star_and_crescent", "keywords": ["islam"] },

View File

@ -56,6 +56,8 @@ const forceExitAfter = timeout => () => {
* @param {string} signalOrEvent The exit signal or event name received on the process.
*/
async function shutdownHandler(signalOrEvent) {
if (process.env.NODE_ENV === 'test') return process.exit(0);
console.warn(`Shutting down: received [${signalOrEvent}] signal`);
for (const listener of shutdownListeners) {

File diff suppressed because one or more lines are too long

View File

@ -55,7 +55,8 @@ export async function getHtml(url: string, accept = 'text/html, */*', timeout =
const _http = new http.Agent({
keepAlive: true,
keepAliveMsecs: 30 * 1000,
});
lookup: cache.lookup,
} as http.AgentOptions);
/**
* Get https non-proxy agent
@ -70,14 +71,14 @@ const _https = new https.Agent({
* Get http proxy or non-proxy agent
*/
export const httpAgent = config.proxy
? new HttpProxyAgent(config.proxy) as unknown as http.Agent
? new HttpProxyAgent(config.proxy)
: _http;
/**
* Get https proxy or non-proxy agent
*/
export const httpsAgent = config.proxy
? new HttpsProxyAgent(config.proxy) as unknown as https.Agent
? new HttpsProxyAgent(config.proxy)
: _https;
/**

View File

@ -5,6 +5,8 @@ import { Note } from '../models/entities/note';
import { Cache } from './cache';
import { isSelfHost, toPunyNullable } from './convert-host';
import { decodeReaction } from './reaction-lib';
import config from '@/config';
import { query } from '@/prelude/url';
const cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12);
@ -59,9 +61,12 @@ export async function populateEmoji(emojiName: string, noteUserHost: string | nu
if (emoji == null) return null;
const isLocal = emoji.host == null;
const url = isLocal ? emoji.url : `${config.url}/proxy/image.png?${query({url: emoji.url})}`;
return {
name: emojiName,
url: emoji.url,
url,
};
}

View File

@ -7,6 +7,8 @@ import { Channel } from './channel';
@Entity()
@Index('IDX_NOTE_TAGS', { synchronize: false })
@Index('IDX_NOTE_MENTIONS', { synchronize: false })
@Index('IDX_NOTE_VISIBLE_USER_IDS', { synchronize: false })
export class Note {
@PrimaryColumn(id())
public id: string;

View File

@ -41,14 +41,12 @@ export const packedBlockingSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this blocking.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the blocking was created.'
},
blockeeId: {
type: 'string' as const,
@ -59,7 +57,6 @@ export const packedBlockingSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'User',
description: 'The blockee.'
},
}
};

View File

@ -51,14 +51,12 @@ export const packedChannelSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this Channel.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the Channel was created.'
},
lastNotedAt: {
type: 'string' as const,
@ -68,7 +66,6 @@ export const packedChannelSchema = {
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
description: 'The name of the Channel.'
},
description: {
type: 'string' as const,

View File

@ -39,14 +39,12 @@ export const packedClipSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this Clip.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the Clip was created.'
},
userId: {
type: 'string' as const,
@ -61,17 +59,14 @@ export const packedClipSchema = {
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
description: 'The name of the Clip.'
},
description: {
type: 'string' as const,
optional: false as const, nullable: true as const,
description: 'The description of the Clip.'
},
isPublic: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
description: 'Whether this Clip is public.',
},
},
};

View File

@ -59,6 +59,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
const { sum } = await this
.createQueryBuilder('file')
.where('file.userId = :id', { id: id })
.andWhere('file.isLink = FALSE')
.select('SUM(file.size)', 'sum')
.getRawOne();
@ -69,6 +70,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
const { sum } = await this
.createQueryBuilder('file')
.where('file.userHost = :host', { host: toPuny(host) })
.andWhere('file.isLink = FALSE')
.select('SUM(file.size)', 'sum')
.getRawOne();
@ -79,6 +81,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
const { sum } = await this
.createQueryBuilder('file')
.where('file.userHost IS NULL')
.andWhere('file.isLink = FALSE')
.select('SUM(file.size)', 'sum')
.getRawOne();
@ -89,6 +92,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
const { sum } = await this
.createQueryBuilder('file')
.where('file.userHost IS NOT NULL')
.andWhere('file.isLink = FALSE')
.select('SUM(file.size)', 'sum')
.getRawOne();
@ -150,44 +154,37 @@ export const packedDriveFileSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this Drive file.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the Drive file was created on Misskey.'
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
description: 'The file name with extension.',
example: 'lenna.jpg'
},
type: {
type: 'string' as const,
optional: false as const, nullable: false as const,
description: 'The MIME type of this Drive file.',
example: 'image/jpeg'
},
md5: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'md5',
description: 'The MD5 hash of this Drive file.',
example: '15eca7fba0480996e2245f5185bf39f2'
},
size: {
type: 'number' as const,
optional: false as const, nullable: false as const,
description: 'The size of this Drive file. (bytes)',
example: 51469
},
isSensitive: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
description: 'Whether this Drive file is sensitive.',
},
blurhash: {
type: 'string' as const,
@ -218,13 +215,11 @@ export const packedDriveFileSchema = {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'url',
description: 'The URL of this Drive file.',
},
thumbnailUrl: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'url',
description: 'The thumbnail URL of this Drive file.',
},
comment: {
type: 'string' as const,
@ -234,26 +229,22 @@ export const packedDriveFileSchema = {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
description: 'The parent folder ID of this Drive file.',
example: 'xxxxxxxxxx',
},
folder: {
type: 'object' as const,
optional: true as const, nullable: true as const,
description: 'The parent folder of this Drive file.',
ref: 'DriveFolder'
},
userId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
description: 'Owner ID of this Drive file.',
example: 'xxxxxxxxxx',
},
user: {
type: 'object' as const,
optional: true as const, nullable: true as const,
description: 'Owner of this Drive file.',
ref: 'User'
}
},

View File

@ -59,35 +59,29 @@ export const packedDriveFolderSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this Drive folder.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the Drive folder was created.'
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
description: 'The folder name.',
},
foldersCount: {
type: 'number' as const,
optional: true as const, nullable: false as const,
description: 'The count of child folders.',
},
filesCount: {
type: 'number' as const,
optional: true as const, nullable: false as const,
description: 'The count of child files.',
},
parentId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
description: 'The parent folder ID of this folder.',
example: 'xxxxxxxxxx',
},
parent: {

View File

@ -95,14 +95,12 @@ export const packedFollowingSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this following.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the following was created.'
},
followeeId: {
type: 'string' as const,
@ -113,7 +111,6 @@ export const packedFollowingSchema = {
type: 'object' as const,
optional: true as const, nullable: false as const,
ref: 'User',
description: 'The followee.'
},
followerId: {
type: 'string' as const,
@ -124,7 +121,6 @@ export const packedFollowingSchema = {
type: 'object' as const,
optional: true as const, nullable: false as const,
ref: 'User',
description: 'The follower.'
},
}
};

View File

@ -34,38 +34,31 @@ export const packedHashtagSchema = {
tag: {
type: 'string' as const,
optional: false as const, nullable: false as const,
description: 'The hashtag name. No # prefixed.',
example: 'misskey',
},
mentionedUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
description: 'Number of all users using this hashtag.'
},
mentionedLocalUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
description: 'Number of local users using this hashtag.'
},
mentionedRemoteUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
description: 'Number of remote users using this hashtag.'
},
attachedUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
description: 'Number of all users who attached this hashtag to profile.'
},
attachedLocalUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
description: 'Number of local users who attached this hashtag to profile.'
},
attachedRemoteUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
description: 'Number of remote users who attached this hashtag to profile.'
},
}
};

View File

@ -53,14 +53,12 @@ export const packedMessagingMessageSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this MessagingMessage.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the MessagingMessage was created.'
},
userId: {
type: 'string' as const,

View File

@ -41,14 +41,12 @@ export const packedMutingSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this muting.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the muting was created.'
},
muteeId: {
type: 'string' as const,
@ -59,7 +57,6 @@ export const packedMutingSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'User',
description: 'The mutee.'
},
}
};

View File

@ -35,14 +35,12 @@ export const packedNoteFavoriteSchema = {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
description: 'The unique identifier for this favorite.',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
description: 'The date that the favorite was created.'
},
note: {
type: 'object' as const,

Some files were not shown because too many files have changed in this diff Show More