Compare commits
No commits in common. "7efa3c724dd6c77017f6567a1b2fe14abf22ace1" and "a7a39328cd1b6889fda4cb31a6b3cf01b9428d74" have entirely different histories.
7efa3c724d
...
a7a39328cd
|
@ -1 +1 @@
|
|||
v16.2.0
|
||||
v16.0.0
|
||||
|
|
4
COPYING
4
COPYING
|
@ -6,6 +6,10 @@ 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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:16.2.0-alpine3.13 AS base
|
||||
FROM node:16.0.0-alpine3.13 AS base
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
|
|
|
@ -99,11 +99,6 @@ 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 -->
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# 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: 38 KiB After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
@ -4,7 +4,7 @@
|
|||
|
||||
import * as fs from 'fs';
|
||||
import * as gulp from 'gulp';
|
||||
import rimraf from 'rimraf';
|
||||
import * as rimraf from 'rimraf';
|
||||
const replace = require('gulp-replace');
|
||||
const terser = require('gulp-terser');
|
||||
const cssnano = require('gulp-cssnano');
|
||||
|
|
|
@ -259,6 +259,8 @@ monthX: "{month}"
|
|||
yearX: "{year}"
|
||||
pages: "الصفحات"
|
||||
integration: "دمج"
|
||||
connectSerice: "أوصل"
|
||||
disconnectSerice: "قطع الاتصال"
|
||||
enableLocalTimeline: "تفعيل الخيط المحلي"
|
||||
enableGlobalTimeline: "تفعيل الخيط الزمني الشامل"
|
||||
disablingTimelinesInfo: "سيتمكن المسؤولون ومن تعديل دائمًا و من الوصول إلى جميع المخططات الزمنية ، حتى إذا لم يتم تمكينها."
|
||||
|
|
|
@ -269,6 +269,8 @@ 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"
|
||||
|
|
|
@ -279,7 +279,6 @@ 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."
|
||||
|
@ -311,8 +310,8 @@ monthX: "{month}"
|
|||
yearX: "{year}"
|
||||
pages: "Seiten"
|
||||
integration: "Integration"
|
||||
connectService: "Verbinden"
|
||||
disconnectService: "Trennen"
|
||||
connectSerice: "Verbinden"
|
||||
disconnectSerice: "Trennen"
|
||||
enableLocalTimeline: "Lokale Chronik aktivieren"
|
||||
enableGlobalTimeline: "Globale Chronik aktivieren"
|
||||
disablingTimelinesInfo: "Administratoren und Moderatoren haben immer Zugriff auf alle Chroniken, auch wenn diese deaktiviert sind."
|
||||
|
@ -326,7 +325,6 @@ 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."
|
||||
|
@ -548,8 +546,6 @@ 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"
|
||||
|
@ -735,11 +731,9 @@ 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"
|
||||
|
|
|
@ -279,7 +279,6 @@ 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."
|
||||
|
@ -311,8 +310,8 @@ monthX: "{month}"
|
|||
yearX: "{year} /"
|
||||
pages: "Pages"
|
||||
integration: "Integration"
|
||||
connectService: "Connect"
|
||||
disconnectService: "Disconnect"
|
||||
connectSerice: "Connect"
|
||||
disconnectSerice: "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."
|
||||
|
@ -326,7 +325,6 @@ 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."
|
||||
|
@ -548,8 +546,6 @@ 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"
|
||||
|
|
|
@ -309,6 +309,8 @@ 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"
|
||||
|
|
|
@ -279,7 +279,6 @@ 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."
|
||||
|
@ -311,8 +310,8 @@ monthX: "{month}"
|
|||
yearX: "{year}"
|
||||
pages: "Pages"
|
||||
integration: "Intégrations"
|
||||
connectService: "Connexion"
|
||||
disconnectService: "Déconnexion"
|
||||
connectSerice: "Connecter"
|
||||
disconnectSerice: "Déconnecter"
|
||||
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."
|
||||
|
@ -547,8 +546,6 @@ 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"
|
||||
|
|
1388
locales/id-ID.yml
1388
locales/id-ID.yml
File diff suppressed because it is too large
Load Diff
|
@ -21,7 +21,6 @@ const languages = [
|
|||
'en-US',
|
||||
'es-ES',
|
||||
'fr-FR',
|
||||
'id-ID',
|
||||
'ja-JP',
|
||||
'ja-KS',
|
||||
'kab-KAB',
|
||||
|
|
|
@ -274,7 +274,6 @@ 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"
|
||||
|
@ -306,8 +305,8 @@ monthX: "{month}"
|
|||
yearX: "{year}"
|
||||
pages: "Pagine"
|
||||
integration: "App collegate"
|
||||
connectService: "Connessione"
|
||||
disconnectService: "Disconnessione "
|
||||
connectSerice: "Connetti"
|
||||
disconnectSerice: "Disconnetti"
|
||||
enableLocalTimeline: "Abilita Timeline locale"
|
||||
enableGlobalTimeline: "Abilita Timeline federata"
|
||||
disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e i moderatori potranno sempre accederci."
|
||||
|
@ -534,8 +533,6 @@ 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"
|
||||
|
|
|
@ -311,8 +311,8 @@ monthX: "{month}月"
|
|||
yearX: "{year}年"
|
||||
pages: "ページ"
|
||||
integration: "連携"
|
||||
connectService: "接続する"
|
||||
disconnectService: "切断する"
|
||||
connectSerice: "接続する"
|
||||
disconnectSerice: "切断する"
|
||||
enableLocalTimeline: "ローカルタイムラインを有効にする"
|
||||
enableGlobalTimeline: "グローバルタイムラインを有効にする"
|
||||
disablingTimelinesInfo: "これらのタイムラインを無効化しても、利便性のため管理者およびモデレーターは引き続き利用することができます。"
|
||||
|
@ -326,7 +326,6 @@ driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのド
|
|||
inMb: "メガバイト単位"
|
||||
iconUrl: "アイコン画像のURL (faviconなど)"
|
||||
bannerUrl: "バナー画像のURL"
|
||||
backgroundImageUrl: "背景画像のURL"
|
||||
basicInfo: "基本情報"
|
||||
pinnedUsers: "ピン留めユーザー"
|
||||
pinnedUsersDescription: "「みつける」ページなどにピン留めしたいユーザーを改行で区切って記述します。"
|
||||
|
|
|
@ -308,6 +308,8 @@ monthX: "{month}月"
|
|||
yearX: "{year}年"
|
||||
pages: "ページ"
|
||||
integration: "連携"
|
||||
connectSerice: "つなぐ"
|
||||
disconnectSerice: "切ってまう"
|
||||
enableLocalTimeline: "ローカルタイムラインを使えるようにする"
|
||||
enableGlobalTimeline: "グローバルタイムラインを使えるようにする"
|
||||
disablingTimelinesInfo: "ここらへんのタイムラインを使えんようにしてしもても、管理者とモデレーターは使えるままになってるで、そうやなかったら不便やからな。"
|
||||
|
|
|
@ -279,7 +279,6 @@ emptyDrive: "드라이브가 비어 있습니다"
|
|||
emptyFolder: "폴더가 비어 있습니다"
|
||||
unableToDelete: "삭제할 수 없습니다"
|
||||
inputNewFileName: "바꿀 파일명을 입력해 주세요"
|
||||
inputNewDescription: "새 캡션을 입력해 주세요"
|
||||
inputNewFolderName: "바꿀 폴더명을 입력해 주세요"
|
||||
circularReferenceFolder: "지정한 폴더가 이동할 폴더의 하위 폴더입니다."
|
||||
hasChildFilesOrFolders: "이 폴더는 비어있지 않기 때문에 삭제할 수 없습니다."
|
||||
|
@ -311,8 +310,8 @@ monthX: "{month}월"
|
|||
yearX: "{year}년"
|
||||
pages: "페이지"
|
||||
integration: "연동"
|
||||
connectService: "계정 연동"
|
||||
disconnectService: "계정 연동 해제"
|
||||
connectSerice: "접속"
|
||||
disconnectSerice: "연결 끊기"
|
||||
enableLocalTimeline: "로컬 타임라인 활성화"
|
||||
enableGlobalTimeline: "글로벌 타임라인 활성화"
|
||||
disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리자 및 모더레이터는 계속 사용할 수 있습니다."
|
||||
|
@ -326,7 +325,6 @@ driveCapacityPerRemoteAccount: "리모트 유저 한 명당 드라이브 용량"
|
|||
inMb: "메가바이트 단위"
|
||||
iconUrl: "아이콘 URL"
|
||||
bannerUrl: "배너 이미지 URL"
|
||||
backgroundImageUrl: "배경 이미지 URL"
|
||||
basicInfo: "기본 정보"
|
||||
pinnedUsers: "고정된 유저"
|
||||
pinnedUsersDescription: "\"발견하기\" 페이지 등에 고정하고 싶은 유저를 한 줄에 한 명씩 적습니다."
|
||||
|
@ -548,8 +546,6 @@ disablePlayer: "플레이어 닫기"
|
|||
expandTweet: "트윗 확장하기"
|
||||
themeEditor: "테마 에디터"
|
||||
description: "설명"
|
||||
describeFile: "캡션 추가"
|
||||
enterFileDescription: "캡션 입력"
|
||||
author: "작성자"
|
||||
leaveConfirm: "저장하지 않은 변경사항이 있습니다. 취소하시겠습니까?"
|
||||
manage: "관리"
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
---
|
||||
_lang_: "Nederlands"
|
||||
headlineMisskey: "Netwerk verbonden door notities"
|
||||
|
|
|
@ -7,7 +7,6 @@ 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!"
|
||||
|
@ -66,7 +65,6 @@ 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"
|
||||
|
@ -135,11 +133,9 @@ 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"
|
||||
|
@ -183,7 +179,6 @@ 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"
|
||||
|
@ -276,7 +271,6 @@ 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."
|
||||
|
@ -297,17 +291,16 @@ 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."
|
||||
|
@ -339,7 +332,6 @@ 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"
|
||||
|
@ -366,7 +358,6 @@ 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"
|
||||
|
@ -406,7 +397,6 @@ 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ść"
|
||||
|
@ -429,7 +419,6 @@ 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}"
|
||||
|
@ -443,7 +432,6 @@ 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"
|
||||
|
@ -465,8 +453,6 @@ 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"
|
||||
|
@ -533,8 +519,6 @@ 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"
|
||||
|
@ -556,7 +540,6 @@ 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"
|
||||
|
@ -569,7 +552,6 @@ 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"
|
||||
|
@ -640,7 +622,6 @@ 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"
|
||||
|
@ -649,7 +630,6 @@ 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"
|
||||
|
@ -659,107 +639,26 @@ 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."
|
||||
|
@ -809,7 +708,6 @@ _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"
|
||||
|
@ -1074,21 +972,16 @@ _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:
|
||||
|
@ -1103,7 +996,6 @@ _instanceCharts:
|
|||
_timelines:
|
||||
home: "Strona główna"
|
||||
local: "Lokalne"
|
||||
social: "Społeczność"
|
||||
global: "Globalna"
|
||||
_rooms:
|
||||
roomOf: "Pokój {user}"
|
||||
|
@ -1474,8 +1366,6 @@ _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"
|
||||
|
|
|
@ -309,6 +309,8 @@ monthX: "{month} месяц"
|
|||
yearX: "{year} год"
|
||||
pages: "Страницы"
|
||||
integration: "Интеграция"
|
||||
connectSerice: "Соединение"
|
||||
disconnectSerice: "Отключение"
|
||||
enableLocalTimeline: "Включить локальную ленту"
|
||||
enableGlobalTimeline: "Включить глобальную ленту"
|
||||
disablingTimelinesInfo: "У администраторов и модераторов есть доступ ко всем лентам, даже если они отключены."
|
||||
|
|
|
@ -307,6 +307,8 @@ monthX: "{month}"
|
|||
yearX: "{year}"
|
||||
pages: "Сторінки"
|
||||
integration: "Інтеграція"
|
||||
connectSerice: "Під’єднати"
|
||||
disconnectSerice: "Відключитися"
|
||||
enableLocalTimeline: "Увімкнути локальну стрічку"
|
||||
enableGlobalTimeline: "Увімкнути глобальну стрічку"
|
||||
disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх стрічок, навіть якщо вони вимкнуті."
|
||||
|
|
|
@ -279,7 +279,6 @@ emptyDrive: "驱动器为空"
|
|||
emptyFolder: "空文件夹"
|
||||
unableToDelete: "无法删除"
|
||||
inputNewFileName: "请输入新文件名"
|
||||
inputNewDescription: "请输入新标题"
|
||||
inputNewFolderName: "请输入新文件名"
|
||||
circularReferenceFolder: "目标文件夹是您要移动的文件夹的子文件夹。"
|
||||
hasChildFilesOrFolders: "此文件夹不为空,无法删除。"
|
||||
|
@ -311,8 +310,8 @@ monthX: "{month}月"
|
|||
yearX: "{year}年"
|
||||
pages: "页面"
|
||||
integration: "关联"
|
||||
connectService: "连接"
|
||||
disconnectService: "断开连接"
|
||||
connectSerice: "连接"
|
||||
disconnectSerice: "断开连接"
|
||||
enableLocalTimeline: "启用本地时间线功能"
|
||||
enableGlobalTimeline: "启用全局时间线"
|
||||
disablingTimelinesInfo: "即使时间线功能被禁用,出于便利性的原因,管理员和数据图表也可以继续使用。"
|
||||
|
@ -326,7 +325,6 @@ driveCapacityPerRemoteAccount: "每个远程用户的网盘容量"
|
|||
inMb: "以兆字节(MegaByte)为单位"
|
||||
iconUrl: "图标URL"
|
||||
bannerUrl: "Banner URL"
|
||||
backgroundImageUrl: "背景图URL"
|
||||
basicInfo: "基本信息"
|
||||
pinnedUsers: "置顶用户"
|
||||
pinnedUsersDescription: "在「发现」页面中使用换行标记想要置顶的用户。"
|
||||
|
@ -548,8 +546,6 @@ disablePlayer: "关闭播放器"
|
|||
expandTweet: "展开贴文"
|
||||
themeEditor: "主题编辑器"
|
||||
description: "描述"
|
||||
describeFile: "添加标题"
|
||||
enterFileDescription: "输入标题"
|
||||
author: "作者"
|
||||
leaveConfirm: "存在未保存的更改。要放弃更改吗?"
|
||||
manage: "管理"
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
---
|
||||
_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: "實例"
|
||||
|
@ -93,9 +92,9 @@ followRequestPending: "追隨許可批准中"
|
|||
enterEmoji: "輸入表情符號"
|
||||
renote: "轉發"
|
||||
unrenote: "取消轉發"
|
||||
renoted: "轉傳成功"
|
||||
renoted: "轉發成功"
|
||||
cantRenote: "無法轉發此貼文。"
|
||||
cantReRenote: "無法轉傳之前已經轉傳過的內容。"
|
||||
cantReRenote: "無法轉發之前已經轉發過的內容。"
|
||||
quote: "引用"
|
||||
pinnedNote: "已置頂的貼文"
|
||||
pinned: "置頂"
|
||||
|
@ -310,6 +309,8 @@ monthX: "{month}月"
|
|||
yearX: "{year}年"
|
||||
pages: "頁面"
|
||||
integration: "整合"
|
||||
connectSerice: "連線"
|
||||
disconnectSerice: "中斷連線"
|
||||
enableLocalTimeline: "開啟本地時間軸"
|
||||
enableGlobalTimeline: "啟用公開時間軸"
|
||||
disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和協調人仍可以繼續使用,以方便您。"
|
||||
|
@ -732,7 +733,6 @@ noBotProtectionWarning: "尚未設定Bot防護。"
|
|||
configure: "設定"
|
||||
expiration: "期限"
|
||||
middle: "中"
|
||||
emailNotConfiguredWarning: "沒有設定電子郵件地址"
|
||||
_ad:
|
||||
back: "返回"
|
||||
_gallery:
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
113
package.json
113
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||
"version": "12.83.0",
|
||||
"version": "12.81.0",
|
||||
"codename": "indigo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -30,52 +30,51 @@
|
|||
"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.14.3",
|
||||
"@babel/plugin-transform-runtime": "7.13.15",
|
||||
"@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.1.2",
|
||||
"@sinonjs/fake-timers": "7.0.5",
|
||||
"@syuilo/aiscript": "0.11.1",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/bull": "3.15.1",
|
||||
"@types/cbor": "6.0.0",
|
||||
"@types/cbor": "5.0.1",
|
||||
"@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.29",
|
||||
"@types/is-url": "1.2.28",
|
||||
"@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.3",
|
||||
"@types/koa-bodyparser": "4.3.1",
|
||||
"@types/koa": "2.13.1",
|
||||
"@types/koa-bodyparser": "4.3.0",
|
||||
"@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": "7.0.0",
|
||||
"@types/koa-views": "2.0.4",
|
||||
"@types/koa__cors": "3.0.2",
|
||||
"@types/koa__multer": "2.0.2",
|
||||
"@types/koa__router": "8.0.4",
|
||||
"@types/markdown-it": "12.0.2",
|
||||
"@types/matter-js": "0.14.12",
|
||||
"@types/markdown-it": "12.0.1",
|
||||
"@types/matter-js": "0.14.11",
|
||||
"@types/mocha": "8.2.2",
|
||||
"@types/node": "15.12.2",
|
||||
"@types/node": "14.14.41",
|
||||
"@types/node-fetch": "2.5.10",
|
||||
"@types/nodemailer": "6.4.2",
|
||||
"@types/nodemailer": "6.4.1",
|
||||
"@types/nprogress": "0.2.0",
|
||||
"@types/oauth": "0.9.1",
|
||||
"@types/parse5": "6.0.0",
|
||||
|
@ -86,12 +85,12 @@
|
|||
"@types/qrcode": "1.4.0",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/ratelimiter": "3.4.1",
|
||||
"@types/redis": "2.8.29",
|
||||
"@types/rename": "1.0.3",
|
||||
"@types/redis": "2.8.28",
|
||||
"@types/rename": "1.0.2",
|
||||
"@types/request-stats": "3.0.0",
|
||||
"@types/rimraf": "3.0.0",
|
||||
"@types/seedrandom": "2.4.28",
|
||||
"@types/sharp": "0.28.3",
|
||||
"@types/sharp": "0.28.0",
|
||||
"@types/sinonjs__fake-timers": "6.0.2",
|
||||
"@types/speakeasy": "2.0.5",
|
||||
"@types/throttle-debounce": "2.1.0",
|
||||
|
@ -102,46 +101,46 @@
|
|||
"@types/webpack": "5.28.0",
|
||||
"@types/webpack-stream": "3.2.12",
|
||||
"@types/websocket": "1.0.2",
|
||||
"@types/ws": "7.4.4",
|
||||
"@typescript-eslint/parser": "4.26.1",
|
||||
"@vue/compiler-sfc": "3.1.1",
|
||||
"@types/ws": "7.4.1",
|
||||
"@typescript-eslint/parser": "4.22.0",
|
||||
"@vue/compiler-sfc": "3.0.11",
|
||||
"abort-controller": "3.0.0",
|
||||
"apexcharts": "3.27.1",
|
||||
"apexcharts": "3.26.1",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autosize": "4.0.4",
|
||||
"autosize": "4.0.2",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.923.0",
|
||||
"aws-sdk": "2.892.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "1.1.3",
|
||||
"broadcast-channel": "3.6.0",
|
||||
"bull": "3.22.7",
|
||||
"broadcast-channel": "3.5.3",
|
||||
"bull": "3.22.3",
|
||||
"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.2.0",
|
||||
"concurrently": "6.0.2",
|
||||
"content-disposition": "0.5.3",
|
||||
"core-js": "3.14.0",
|
||||
"core-js": "3.11.0",
|
||||
"crc-32": "1.2.0",
|
||||
"css-loader": "5.2.6",
|
||||
"cssnano": "5.0.5",
|
||||
"css-loader": "5.2.4",
|
||||
"cssnano": "5.0.1",
|
||||
"dateformat": "4.5.1",
|
||||
"diskusage": "1.1.3",
|
||||
"escape-regexp": "0.0.1",
|
||||
"eslint": "7.28.0",
|
||||
"eslint-plugin-vue": "7.10.0",
|
||||
"eslint": "7.25.0",
|
||||
"eslint-plugin-vue": "7.9.0",
|
||||
"eventemitter3": "4.0.7",
|
||||
"feed": "4.2.2",
|
||||
"file-type": "16.5.0",
|
||||
"file-type": "16.3.0",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"glob": "7.1.7",
|
||||
"glob": "7.1.6",
|
||||
"got": "11.8.2",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-cssnano": "2.1.3",
|
||||
"gulp-rename": "2.0.0",
|
||||
"gulp-replace": "1.1.3",
|
||||
"gulp-replace": "1.1.1",
|
||||
"gulp-terser": "2.0.1",
|
||||
"gulp-tslint": "8.1.4",
|
||||
"hard-source-webpack-plugin": "0.13.1",
|
||||
|
@ -149,17 +148,17 @@
|
|||
"http-proxy-agent": "4.0.1",
|
||||
"http-signature": "1.3.5",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"idb-keyval": "5.0.6",
|
||||
"idb-keyval": "5.0.5",
|
||||
"insert-text-at-cursor": "0.3.0",
|
||||
"is-root": "2.1.0",
|
||||
"is-svg": "4.3.1",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsdom": "16.6.0",
|
||||
"jsdom": "16.5.3",
|
||||
"json5": "2.2.0",
|
||||
"json5-loader": "4.0.1",
|
||||
"jsonld": "4.0.1",
|
||||
"jsrsasign": "8.0.20",
|
||||
"katex": "0.13.11",
|
||||
"katex": "0.13.3",
|
||||
"koa": "2.13.1",
|
||||
"koa-bodyparser": "4.3.0",
|
||||
"koa-favicon": "2.1.0",
|
||||
|
@ -174,24 +173,23 @@
|
|||
"markdown-it": "12.0.6",
|
||||
"markdown-it-anchor": "7.1.0",
|
||||
"matter-js": "0.17.1",
|
||||
"mfm-js": "0.18.0",
|
||||
"misskey-js": "0.0.4",
|
||||
"mocha": "8.4.0",
|
||||
"mfm-js": "0.16.3",
|
||||
"mocha": "8.3.2",
|
||||
"moji": "0.5.1",
|
||||
"ms": "2.1.3",
|
||||
"multer": "1.4.2",
|
||||
"nested-property": "4.0.0",
|
||||
"node-fetch": "2.6.1",
|
||||
"nodemailer": "6.6.1",
|
||||
"nodemailer": "6.5.0",
|
||||
"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.3.0",
|
||||
"postcss-loader": "5.3.0",
|
||||
"postcss": "8.2.12",
|
||||
"postcss-loader": "5.2.0",
|
||||
"prismjs": "1.23.0",
|
||||
"probe-image-size": "7.2.1",
|
||||
"probe-image-size": "7.1.0",
|
||||
"promise-limit": "2.7.0",
|
||||
"promise-sequential": "1.1.1",
|
||||
"pug": "3.0.2",
|
||||
|
@ -200,7 +198,7 @@
|
|||
"qrcode": "1.4.4",
|
||||
"random-seed": "0.3.0",
|
||||
"ratelimiter": "3.4.1",
|
||||
"re2": "1.16.0",
|
||||
"re2": "1.15.9",
|
||||
"reconnecting-websocket": "4.4.0",
|
||||
"redis": "3.1.2",
|
||||
"redis-lock": "0.1.4",
|
||||
|
@ -212,36 +210,35 @@
|
|||
"rimraf": "3.0.2",
|
||||
"rndstr": "1.0.0",
|
||||
"s-age": "1.1.2",
|
||||
"sass": "1.34.1",
|
||||
"sass-loader": "12.0.0",
|
||||
"sass": "1.32.11",
|
||||
"sass-loader": "11.0.1",
|
||||
"seedrandom": "3.0.5",
|
||||
"sharp": "0.28.3",
|
||||
"sharp": "0.28.1",
|
||||
"speakeasy": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"style-loader": "2.0.0",
|
||||
"summaly": "2.4.0",
|
||||
"syslog-pro": "1.0.0",
|
||||
"systeminformation": "5.7.4",
|
||||
"systeminformation": "5.6.12",
|
||||
"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.2.3",
|
||||
"ts-node": "10.0.0",
|
||||
"tsc-alias": "1.3.2",
|
||||
"ts-loader": "9.1.1",
|
||||
"ts-node": "9.1.1",
|
||||
"tsc-alias": "1.2.10",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"tslint": "6.1.3",
|
||||
"tslint-sonarts": "1.9.0",
|
||||
"twemoji-parser": "13.1.0",
|
||||
"typeorm": "0.2.34",
|
||||
"typescript": "4.3.2",
|
||||
"typeorm": "0.2.32",
|
||||
"typescript": "4.2.4",
|
||||
"ulid": "2.3.0",
|
||||
"uuid": "8.3.2",
|
||||
"v-debounce": "0.1.2",
|
||||
"vanilla-tilt": "1.7.0",
|
||||
"vue": "3.1.1",
|
||||
"vue": "3.0.11",
|
||||
"vue-color": "2.8.1",
|
||||
"vue-json-pretty": "1.7.1",
|
||||
"vue-loader": "16.1.2",
|
||||
|
@ -251,10 +248,10 @@
|
|||
"vue-svg-loader": "0.17.0-beta.2",
|
||||
"vuedraggable": "4.0.1",
|
||||
"web-push": "3.4.4",
|
||||
"webpack": "5.38.1",
|
||||
"webpack-cli": "4.7.2",
|
||||
"webpack": "5.35.1",
|
||||
"webpack-cli": "4.6.0",
|
||||
"websocket": "1.0.34",
|
||||
"ws": "7.4.6",
|
||||
"ws": "7.4.5",
|
||||
"xev": "2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, h, PropType, TransitionGroup } from 'vue';
|
||||
import { defineComponent, h, TransitionGroup } from 'vue';
|
||||
import MkAd from '@client/components/global/ad.vue';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
items: {
|
||||
type: Array as PropType<{ id: string; createdAt: string; _shouldInsertAd_: boolean; }[]>,
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
direction: {
|
||||
|
|
|
@ -139,7 +139,7 @@ export default defineComponent({
|
|||
});
|
||||
}
|
||||
|
||||
this.connection = os.stream.useChannel('drive');
|
||||
this.connection = os.stream.useSharedConnection('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
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<MkModal ref="modal" :manual-showing="manualShowing" :src="src" :front="true" @click="$refs.modal.close()" @opening="opening" @close="$emit('close')" @closed="$emit('closed')">
|
||||
<MkModal ref="modal" :manual-showing="manualShowing" :src="src" @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>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<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">
|
||||
|
|
|
@ -71,7 +71,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.connection = os.stream.useChannel('main');
|
||||
this.connection = os.stream.useSharedConnection('main');
|
||||
|
||||
this.connection.on('follow', this.onFollowChange);
|
||||
this.connection.on('unfollow', this.onFollowChange);
|
||||
|
|
|
@ -87,6 +87,8 @@ export default defineComponent({
|
|||
> .icon {
|
||||
padding-left: 2px;
|
||||
font-size: .9em;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,238 +0,0 @@
|
|||
<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>
|
|
@ -109,7 +109,7 @@ export default defineComponent({
|
|||
|
||||
this.readObserver.observe(this.$el);
|
||||
|
||||
this.connection = os.stream.useChannel('main');
|
||||
this.connection = os.stream.useSharedConnection('main');
|
||||
this.connection.on('readAllNotifications', () => this.readObserver.unobserve(this.$el));
|
||||
}
|
||||
},
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
<XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/>
|
||||
</XList>
|
||||
|
||||
<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' }">
|
||||
<button class="_buttonPrimary" 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>
|
||||
</MkButton>
|
||||
</button>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
@ -28,14 +28,12 @@ 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: [
|
||||
|
@ -89,7 +87,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.connection = os.stream.useChannel('main');
|
||||
this.connection = os.stream.useSharedConnection('main');
|
||||
this.connection.on('notification', this.onNotification);
|
||||
},
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ export default defineComponent({
|
|||
text: file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive,
|
||||
icon: file.isSensitive ? 'fas fa-eye-slash' : 'fas fa-eye',
|
||||
action: () => { this.toggleSensitive(file) }
|
||||
}, {
|
||||
},{
|
||||
text: this.$ts.describeFile,
|
||||
icon: 'fas fa-i-cursor',
|
||||
action: () => { this.describe(file) }
|
||||
|
|
|
@ -92,33 +92,33 @@ export default defineComponent({
|
|||
this.query = {
|
||||
antennaId: this.antenna
|
||||
};
|
||||
this.connection = os.stream.useChannel('antenna', {
|
||||
this.connection = os.stream.connectToChannel('antenna', {
|
||||
antennaId: this.antenna
|
||||
});
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'home') {
|
||||
endpoint = 'notes/timeline';
|
||||
this.connection = os.stream.useChannel('homeTimeline');
|
||||
this.connection = os.stream.useSharedConnection('homeTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
|
||||
this.connection2 = os.stream.useChannel('main');
|
||||
this.connection2 = os.stream.useSharedConnection('main');
|
||||
this.connection2.on('follow', onChangeFollowing);
|
||||
this.connection2.on('unfollow', onChangeFollowing);
|
||||
} else if (this.src == 'local') {
|
||||
endpoint = 'notes/local-timeline';
|
||||
this.connection = os.stream.useChannel('localTimeline');
|
||||
this.connection = os.stream.useSharedConnection('localTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'social') {
|
||||
endpoint = 'notes/hybrid-timeline';
|
||||
this.connection = os.stream.useChannel('hybridTimeline');
|
||||
this.connection = os.stream.useSharedConnection('hybridTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'global') {
|
||||
endpoint = 'notes/global-timeline';
|
||||
this.connection = os.stream.useChannel('globalTimeline');
|
||||
this.connection = os.stream.useSharedConnection('globalTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'mentions') {
|
||||
endpoint = 'notes/mentions';
|
||||
this.connection = os.stream.useChannel('main');
|
||||
this.connection = os.stream.useSharedConnection('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.useChannel('main');
|
||||
this.connection = os.stream.useSharedConnection('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.useChannel('userList', {
|
||||
this.connection = os.stream.connectToChannel('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.useChannel('channel', {
|
||||
this.connection = os.stream.connectToChannel('channel', {
|
||||
channelId: this.channel
|
||||
});
|
||||
this.connection.on('note', prepend);
|
||||
|
|
|
@ -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="qzhlnise" :class="{ front }" v-hotkey.global="keymap" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
|
||||
<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 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,11 +41,6 @@ export default defineComponent({
|
|||
},
|
||||
position: {
|
||||
required: false
|
||||
},
|
||||
front: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
emits: ['opening', 'click', 'esc', 'close', 'closed'],
|
||||
|
@ -229,14 +224,14 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
|
||||
.qzhlnise {
|
||||
.mk-modal {
|
||||
> .bg {
|
||||
z-index: 10000;
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
> .content:not(.popup) {
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
z-index: 20000;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
@ -268,25 +263,11 @@ export default defineComponent({
|
|||
|
||||
> .content.popup {
|
||||
position: absolute;
|
||||
z-index: 10000;
|
||||
z-index: 20000;
|
||||
|
||||
&.fixed {
|
||||
position: fixed;
|
||||
}
|
||||
}
|
||||
|
||||
&.front {
|
||||
> .bg {
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
> .content:not(.popup) {
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
> .content.popup {
|
||||
z-index: 20000;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -163,6 +163,8 @@ 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') :
|
||||
|
@ -294,7 +296,7 @@ if ($i) {
|
|||
}
|
||||
}
|
||||
|
||||
const main = stream.useChannel('main', null, 'System');
|
||||
const main = stream.useSharedConnection('main', 'System');
|
||||
|
||||
// 自分の情報が更新されたとき
|
||||
main.on('meUpdated', i => {
|
||||
|
@ -356,6 +358,10 @@ if ($i) {
|
|||
sound.play('channel');
|
||||
});
|
||||
|
||||
main.on('readAllAnnouncements', () => {
|
||||
updateAccount({ hasUnreadAnnouncement: false });
|
||||
});
|
||||
|
||||
// トークンが再生成されたとき
|
||||
// このままではMisskeyが利用できないので強制的にサインアウトさせる
|
||||
main.on('myTokenRegenerated', () => {
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
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: Misskey.entities.InstanceMetadata = reactive(data ? JSON.parse(data) : {
|
||||
export const instance: Instance = reactive(data ? JSON.parse(data) : {
|
||||
// TODO: set default values
|
||||
});
|
||||
|
||||
|
|
|
@ -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 { apiUrl, debug, url } from '@client/config';
|
||||
import Stream from '@client/scripts/stream';
|
||||
import { apiUrl, debug } 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 Misskey.Stream(url, $i));
|
||||
export const stream = markRaw(new Stream());
|
||||
|
||||
export const pendingApiRequestsCount = ref(0);
|
||||
let apiRequestsCount = 0; // for debug
|
||||
|
@ -20,11 +20,7 @@ export const apiRequests = ref([]); // for debug
|
|||
|
||||
export const windows = new Map();
|
||||
|
||||
const apiClient = new Misskey.api.APIClient({
|
||||
origin: url,
|
||||
});
|
||||
|
||||
export const api = ((endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) => {
|
||||
export function api(endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) {
|
||||
pendingApiRequestsCount.value++;
|
||||
|
||||
const onFinally = () => {
|
||||
|
@ -60,7 +56,7 @@ export const api = ((endpoint: string, data: Record<string, any> = {}, token?: s
|
|||
if (res.status === 200) {
|
||||
resolve(body);
|
||||
if (debug) {
|
||||
log!.res = markRaw(JSON.parse(JSON.stringify(body)));
|
||||
log!.res = markRaw(body);
|
||||
log!.state = 'success';
|
||||
}
|
||||
} else if (res.status === 204) {
|
||||
|
@ -94,15 +90,17 @@ export const api = ((endpoint: string, data: Record<string, any> = {}, token?: s
|
|||
promise.then(onFinally, onFinally);
|
||||
|
||||
return promise;
|
||||
}) as typeof apiClient.request;
|
||||
}
|
||||
|
||||
export const apiWithDialog = ((
|
||||
export function 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, null, (e) => {
|
||||
promiseDialog(promise, onSuccess, onFailure ? onFailure : (e) => {
|
||||
dialog({
|
||||
type: 'error',
|
||||
text: e.message + '\n' + (e as any).id,
|
||||
|
@ -110,7 +108,7 @@ export const apiWithDialog = ((
|
|||
});
|
||||
|
||||
return promise;
|
||||
}) as typeof api;
|
||||
}
|
||||
|
||||
export function promiseDialog<T extends Promise<any>>(
|
||||
promise: T,
|
||||
|
|
|
@ -90,7 +90,7 @@ export default defineComponent({
|
|||
stats: null,
|
||||
serverInfo: null,
|
||||
connection: null,
|
||||
queueConnection: os.stream.useChannel('queueStats'),
|
||||
queueConnection: os.stream.useSharedConnection('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.useChannel('serverStats');
|
||||
this.connection = os.stream.useSharedConnection('serverStats');
|
||||
this.connection.on('stats', this.onStats);
|
||||
this.connection.on('statsLog', this.onStatsLog);
|
||||
this.connection.send('requestLog', {
|
||||
|
|
|
@ -92,7 +92,6 @@ 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', {}),
|
||||
|
|
|
@ -35,7 +35,7 @@ export default defineComponent({
|
|||
title: this.$ts.jobQueue,
|
||||
icon: 'fas fa-clipboard-list',
|
||||
},
|
||||
connection: os.stream.useChannel('queueStats'),
|
||||
connection: os.stream.useSharedConnection('queueStats'),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -19,11 +19,6 @@
|
|||
<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>
|
||||
|
@ -93,7 +88,6 @@ export default defineComponent({
|
|||
maintainerEmail: null,
|
||||
iconUrl: null,
|
||||
bannerUrl: null,
|
||||
backgroundImageUrl: null,
|
||||
maxNoteTextLength: 0,
|
||||
enableLocalTimeline: false,
|
||||
enableGlobalTimeline: false,
|
||||
|
@ -112,7 +106,6 @@ 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;
|
||||
|
@ -127,7 +120,6 @@ export default defineComponent({
|
|||
tosUrl: this.tosUrl,
|
||||
iconUrl: this.iconUrl,
|
||||
bannerUrl: this.bannerUrl,
|
||||
backgroundImageUrl: this.backgroundImageUrl,
|
||||
maintainerName: this.maintainerName,
|
||||
maintainerEmail: this.maintainerEmail,
|
||||
maxNoteTextLength: this.maxNoteTextLength,
|
||||
|
|
|
@ -63,7 +63,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.connection = os.stream.useChannel('messagingIndex');
|
||||
this.connection = os.stream.useSharedConnection('messagingIndex');
|
||||
|
||||
this.connection.on('message', this.onMessage);
|
||||
this.connection.on('read', this.onRead);
|
||||
|
|
|
@ -141,7 +141,7 @@ const Component = defineComponent({
|
|||
this.group = group;
|
||||
}
|
||||
|
||||
this.connection = os.stream.useChannel('messaging', {
|
||||
this.connection = os.stream.connectToChannel('messaging', {
|
||||
otherparty: this.user ? this.user.id : undefined,
|
||||
group: this.group ? this.group.id : undefined,
|
||||
});
|
||||
|
|
|
@ -350,9 +350,6 @@ export default defineComponent({
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@use "sass:math";
|
||||
|
||||
.xqnhankfuuilcwvhgsopeqncafzsquya {
|
||||
text-align: center;
|
||||
|
||||
|
@ -391,11 +388,11 @@ export default defineComponent({
|
|||
font-size: 0.8em;
|
||||
|
||||
&:first-child {
|
||||
margin-left: -(math.div($gap, 2));
|
||||
margin-left: -($gap / 2);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: -(math.div($gap, 2));
|
||||
margin-right: -($gap / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -416,11 +413,11 @@ export default defineComponent({
|
|||
font-size: 12px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: -(math.div($gap, 2));
|
||||
margin-top: -($gap / 2);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: -(math.div($gap, 2));
|
||||
margin-bottom: -($gap / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ export default defineComponent({
|
|||
if (this.connection) {
|
||||
this.connection.dispose();
|
||||
}
|
||||
this.connection = os.stream.useChannel('gamesReversiGame', {
|
||||
this.connection = os.stream.connectToChannel('gamesReversiGame', {
|
||||
gameId: this.game.id
|
||||
});
|
||||
this.connection.on('started', this.onStarted);
|
||||
|
|
|
@ -92,7 +92,7 @@ export default defineComponent({
|
|||
|
||||
mounted() {
|
||||
if (this.$i) {
|
||||
this.connection = os.stream.useChannel('gamesReversi');
|
||||
this.connection = os.stream.useSharedConnection('gamesReversi');
|
||||
|
||||
this.connection.on('invited', this.onInvited);
|
||||
|
||||
|
|
|
@ -220,9 +220,6 @@ export default defineComponent({
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@use "sass:math";
|
||||
|
||||
.uawsfosz {
|
||||
> div {
|
||||
padding: 24px;
|
||||
|
@ -230,12 +227,12 @@ export default defineComponent({
|
|||
> .meter {
|
||||
$size: 12px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: math.div($size, 2);
|
||||
border-radius: ($size / 2);
|
||||
overflow: hidden;
|
||||
|
||||
> div {
|
||||
height: $size;
|
||||
border-radius: math.div($size, 2);
|
||||
border-radius: ($size / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.disconnectService }}</MkButton>
|
||||
<MkButton v-else @click="connectTwitter" primary>{{ $ts.connectService }}</MkButton>
|
||||
<MkButton v-if="integrations.twitter" @click="disconnectTwitter" danger>{{ $ts.disconnectSerice }}</MkButton>
|
||||
<MkButton v-else @click="connectTwitter" primary>{{ $ts.connectSerice }}</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.disconnectService }}</MkButton>
|
||||
<MkButton v-else @click="connectDiscord" primary>{{ $ts.connectService }}</MkButton>
|
||||
<MkButton v-if="integrations.discord" @click="disconnectDiscord" danger>{{ $ts.disconnectSerice }}</MkButton>
|
||||
<MkButton v-else @click="connectDiscord" primary>{{ $ts.connectSerice }}</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.disconnectService }}</MkButton>
|
||||
<MkButton v-else @click="connectGithub" primary>{{ $ts.connectService }}</MkButton>
|
||||
<MkButton v-if="integrations.github" @click="disconnectGithub" danger>{{ $ts.disconnectSerice }}</MkButton>
|
||||
<MkButton v-else @click="connectGithub" primary>{{ $ts.connectSerice }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</FormBase>
|
||||
|
|
|
@ -3,11 +3,6 @@ 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,
|
||||
|
|
|
@ -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.useChannel('main');
|
||||
const connection = os.stream.useSharedConnection('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
|
||||
});
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -146,7 +146,6 @@ hr {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--modalBg);
|
||||
-webkit-backdrop-filter: var(--modalBgFilter);
|
||||
backdrop-filter: var(--modalBgFilter);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
if ($i) {
|
||||
const connection = stream.useChannel('main', null, 'UI');
|
||||
const connection = stream.useSharedConnection('main', 'UI');
|
||||
connection.on('notification', onNotification);
|
||||
}
|
||||
|
||||
|
|
|
@ -121,33 +121,33 @@ export default defineComponent({
|
|||
this.query = {
|
||||
antennaId: this.antenna
|
||||
};
|
||||
this.connection = os.stream.useChannel('antenna', {
|
||||
this.connection = os.stream.connectToChannel('antenna', {
|
||||
antennaId: this.antenna
|
||||
});
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'home') {
|
||||
endpoint = 'notes/timeline';
|
||||
this.connection = os.stream.useChannel('homeTimeline');
|
||||
this.connection = os.stream.useSharedConnection('homeTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
|
||||
this.connection2 = os.stream.useChannel('main');
|
||||
this.connection2 = os.stream.useSharedConnection('main');
|
||||
this.connection2.on('follow', onChangeFollowing);
|
||||
this.connection2.on('unfollow', onChangeFollowing);
|
||||
} else if (this.src == 'local') {
|
||||
endpoint = 'notes/local-timeline';
|
||||
this.connection = os.stream.useChannel('localTimeline');
|
||||
this.connection = os.stream.useSharedConnection('localTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'social') {
|
||||
endpoint = 'notes/hybrid-timeline';
|
||||
this.connection = os.stream.useChannel('hybridTimeline');
|
||||
this.connection = os.stream.useSharedConnection('hybridTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'global') {
|
||||
endpoint = 'notes/global-timeline';
|
||||
this.connection = os.stream.useChannel('globalTimeline');
|
||||
this.connection = os.stream.useSharedConnection('globalTimeline');
|
||||
this.connection.on('note', prepend);
|
||||
} else if (this.src == 'mentions') {
|
||||
endpoint = 'notes/mentions';
|
||||
this.connection = os.stream.useChannel('main');
|
||||
this.connection = os.stream.useSharedConnection('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.useChannel('main');
|
||||
this.connection = os.stream.useSharedConnection('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.useChannel('userList', {
|
||||
this.connection = os.stream.connectToChannel('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.useChannel('channel', {
|
||||
this.connection = os.stream.connectToChannel('channel', {
|
||||
channelId: this.channel
|
||||
});
|
||||
this.connection.on('note', prepend);
|
||||
|
|
|
@ -241,6 +241,7 @@ export default defineComponent({
|
|||
> .text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,7 +309,7 @@ export default defineComponent({
|
|||
> .indicator {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
left: 20px;
|
||||
color: var(--navIndicator);
|
||||
font-size: 8px;
|
||||
animation: blink 1s infinite;
|
||||
|
|
|
@ -65,7 +65,7 @@ export default defineComponent({
|
|||
extends: widget,
|
||||
data() {
|
||||
return {
|
||||
connection: os.stream.useChannel('queueStats'),
|
||||
connection: os.stream.useSharedConnection('queueStats'),
|
||||
inbox: {
|
||||
activeSincePrevTick: 0,
|
||||
active: 0,
|
||||
|
|
|
@ -48,7 +48,7 @@ export default defineComponent({
|
|||
};
|
||||
},
|
||||
mounted() {
|
||||
this.connection = os.stream.useChannel('main');
|
||||
this.connection = os.stream.useSharedConnection('main');
|
||||
|
||||
this.connection.on('driveFileCreated', this.onDriveFileCreated);
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ export default defineComponent({
|
|||
os.api('server-info', {}).then(res => {
|
||||
this.meta = res;
|
||||
});
|
||||
this.connection = os.stream.useChannel('serverStats');
|
||||
this.connection = os.stream.useSharedConnection('serverStats');
|
||||
},
|
||||
unmounted() {
|
||||
this.connection.dispose();
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
# 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.
|
||||
ストリーミングAPIを使うと、リアルタイムで様々な情報(例えばタイムラインに新しい投稿が流れてきた、メッセージが届いた、フォローされた、など)を受け取ったり、様々な操作を行ったりすることができます。
|
||||
|
||||
## Conectarse a streams
|
||||
## ストリームに接続する
|
||||
|
||||
Para usar la API de streaming, primero hay que conectar un **websocket** al servidor de Misskey
|
||||
ストリーミングAPIを利用するには、まずMisskeyサーバーに**websocket**接続する必要があります。
|
||||
|
||||
Conecte el websocket a la URL mencionada abajo, incluyendo la información de autenticación en el parámetro `i`Ej:
|
||||
以下のURLに、`i`というパラメータ名で認証情報を含めて、websocket接続してください。例:
|
||||
```
|
||||
%WS_URL%/streaming?i=xxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
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
|
||||
認証情報は、自分のAPIキーや、アプリケーションからストリームに接続する際はユーザーのアクセストークンのことを指します。
|
||||
|
||||
<div class="ui info">
|
||||
<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>
|
||||
<p><i class="fas fa-info-circle"></i> 認証情報の取得については、<a href="./api">こちらのドキュメント</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 @@ Aquí
|
|||
}
|
||||
```
|
||||
|
||||
Aquí
|
||||
ここで、
|
||||
* `id`には前述したそのチャンネルに接続する際に設定したIDが設定されています。これで、このメッセージがどのチャンネルからのものなのか知ることができます。
|
||||
* `type`にはメッセージの種類が設定されます。チャンネルによって、どのような種類のメッセージが流れてくるかは異なります。
|
||||
* `body`にはメッセージの内容が設定されます。チャンネルによって、どのような内容のメッセージが流れてくるかは異なります。
|
||||
|
@ -98,7 +98,7 @@ Aquí
|
|||
}
|
||||
```
|
||||
|
||||
Aquí
|
||||
ここで、
|
||||
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。これで、このメッセージがどのチャンネルに向けたものなのか識別させることができます。
|
||||
* `type`にはメッセージの種類を設定します。チャンネルによって、どのような種類のメッセージを受け付けるかは異なります。
|
||||
* `body`にはメッセージの内容を設定します。チャンネルによって、どのような内容のメッセージを受け付けるかは異なります。
|
||||
|
@ -115,7 +115,7 @@ Aquí
|
|||
}
|
||||
```
|
||||
|
||||
Aquí
|
||||
ここで、
|
||||
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。
|
||||
|
||||
## ストリームを経由してAPIリクエストする
|
||||
|
@ -136,7 +136,7 @@ Aquí
|
|||
}
|
||||
```
|
||||
|
||||
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 @@ Aquí
|
|||
}
|
||||
```
|
||||
|
||||
Aquí
|
||||
ここで、
|
||||
* `body`内の`id`に、イベントを発生させた投稿のIDが設定されます。
|
||||
* `body`内の`type`に、イベントの種類が設定されます。
|
||||
* `body`内の`body`に、イベントの詳細が設定されます。
|
||||
|
@ -219,7 +219,7 @@ Aquí
|
|||
* `reaction`に、リアクションの種類が設定されます。
|
||||
* `userId`に、リアクションを行ったユーザーのIDが設定されます。
|
||||
|
||||
Ej:
|
||||
例:
|
||||
```json
|
||||
{
|
||||
type: 'noteUpdated',
|
||||
|
@ -239,7 +239,7 @@ Ej:
|
|||
|
||||
* `deletedAt`に、削除日時が設定されます。
|
||||
|
||||
Ej:
|
||||
例:
|
||||
```json
|
||||
{
|
||||
type: 'noteUpdated',
|
||||
|
@ -259,7 +259,7 @@ Ej:
|
|||
* `choice`に、選択肢IDが設定されます。
|
||||
* `userId`に、投票を行ったユーザーのIDが設定されます。
|
||||
|
||||
Ej:
|
||||
例:
|
||||
```json
|
||||
{
|
||||
type: 'noteUpdated',
|
||||
|
@ -289,7 +289,7 @@ Ej:
|
|||
}
|
||||
```
|
||||
|
||||
Aquí
|
||||
ここで、
|
||||
* `id`にキャプチャを解除したい投稿の`id`を設定します。
|
||||
|
||||
このメッセージを送信すると、以後、その投稿に関するイベントは流れてこないようになります。
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# Tema
|
||||
|
||||
Eligiendo un tema, se puede cambiar la apariencia del cliente de Misskey
|
||||
テーマを設定して、Misskeyクライアントの見た目を変更できます。
|
||||
|
||||
## Configuración del tema
|
||||
Configuración > Tema
|
||||
## テーマの設定
|
||||
設定 > テーマ
|
||||
|
||||
## Crear tema
|
||||
El código del tema se guarda como un archivo JSON5. Un ejemplo de tema se puede ver aquí:
|
||||
## テーマを作成する
|
||||
テーマコードはJSON5で記述されたテーマオブジェクトです。 テーマは以下のようなオブジェクトです。
|
||||
``` js
|
||||
{
|
||||
id: '17587283-dd92-4a2c-a22c-be0637c9e22a',
|
||||
|
@ -33,36 +33,36 @@ El código del tema se guarda como un archivo JSON5. Un ejemplo de tema se puede
|
|||
|
||||
```
|
||||
|
||||
* `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.
|
||||
* `id` ... テーマの一意なID。UUIDをおすすめします。
|
||||
* `name` ... テーマ名
|
||||
* `author` ... テーマの作者
|
||||
* `desc` ... テーマの説明(オプション)
|
||||
* `base` ... 明るいテーマか、暗いテーマか
|
||||
* `light`にすると明るいテーマになり、`dark`にすると暗いテーマになります。
|
||||
* テーマはここで設定されたベーステーマを継承します。
|
||||
* `props` ... テーマのスタイル定義。これから説明します。
|
||||
|
||||
### 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.
|
||||
### テーマのスタイル定義
|
||||
`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`があると見なされます。
|
||||
|
||||
#### 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}`
|
||||
#### バリューで使える構文
|
||||
* 16進数で表された色
|
||||
* 例: `#00ff00`
|
||||
* `rgb(r, g, b)`形式で表された色
|
||||
* 例: `rgb(0, 255, 0)`
|
||||
* `rgb(r, g, b, a)`形式で表された透明度を含む色
|
||||
* 例: `rgba(0, 255, 0, 0.5)`
|
||||
* 他のキーの値の参照
|
||||
* `@{キー名}`と書くと他のキーの値の参照になります。`{キー名}`は参照したいキーの名前に置き換えます。
|
||||
* 例: `@panel`
|
||||
* 定数(後述)の参照
|
||||
* `${定数名}`と書くと定数の参照になります。`{定数名}`は参照したい定数の名前に置き換えます。
|
||||
* 例: `$main`
|
||||
* 関数(後述)
|
||||
* `:{関数名}<{引数}<{色}`
|
||||
|
||||
#### 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.
|
||||
#### Constante
|
||||
「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。 キー名を`$`で始めると、そのキーはCSS変数として出力されません。
|
||||
|
||||
#### funciones
|
||||
wip
|
||||
|
|
|
@ -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"
|
||||
全てのローカルユーザーの「ホーム」指定されていない投稿と、サーバーに届いた全てのリモートユーザーの「ホーム」指定されていない投稿
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# AiScript
|
||||
|
||||
## Fungsi
|
||||
Secara bawaan, berjalan sebagai pass dari value.
|
||||
## 関数
|
||||
デフォルトで値渡しです。
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
# Misskey 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.
|
||||
MisskeyAPIを使ってMisskeyクライアント、Misskey連携Webサービス、Bot等(以下「アプリケーション」と呼びます)を開発できます。 ストリーミング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.
|
||||
## アクセストークンの取得
|
||||
基本的に、APIはリクエストにはアクセストークンが必要となります。 APIにリクエストするのが自分自身なのか、不特定の利用者に使ってもらうアプリケーションなのかによって取得手順は異なります。
|
||||
|
||||
* 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" ](#アプリケーション利用者にアクセストークンの発行をリクエストする)
|
||||
* 前者の場合: [「自分自身のアクセストークンを手動発行する」](#自分自身のアクセストークンを手動発行する)に進む
|
||||
* 後者の場合: [「アプリケーション利用者にアクセストークンの発行をリクエストする」](#アプリケーション利用者にアクセストークンの発行をリクエストする)に進む
|
||||
|
||||
### Menerbitkan access token untuk akun kamu sendiri secara manual
|
||||
Kamu dapat membuat access token untuk akun milikmu di Pengaturan > API.
|
||||
### 自分自身のアクセストークンを手動発行する
|
||||
「設定 > API」で、自分のアクセストークンを発行できます。
|
||||
|
||||
[Lanjutkan untuk menggunakan API.](#APIの使い方)
|
||||
[「APIの使い方」へ進む](#APIの使い方)
|
||||
|
||||
### アプリケーション利用者にアクセストークンの発行をリクエストする
|
||||
アプリケーション利用者のアクセストークンを取得するには、以下の手順で発行をリクエストします。
|
||||
|
@ -49,7 +49,7 @@ UUIDを生成する。以後これをセッションIDと呼びます。
|
|||
* `token` ... ユーザーのアクセストークン
|
||||
* `user` ... ユーザーの情報
|
||||
|
||||
[Lanjutkan untuk menggunakan API.](#APIの使い方)
|
||||
[「APIの使い方」へ進む](#APIの使い方)
|
||||
|
||||
## APIの使い方
|
||||
**APIはすべてPOSTで、リクエスト/レスポンスともにJSON形式です。RESTではありません。** アクセストークンは、`i`というパラメータ名でリクエストに含めます。
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# プラグインの作成
|
||||
Misskey Webクライアントのプラグイン機能を使うと、クライアントを拡張し、様々な機能を追加できます。 ここではプラグインの作成にあたってのメタデータ定義や、AiScript APIリファレンスを掲載します。
|
||||
|
||||
## Metadata
|
||||
## メタデータ
|
||||
プラグインは、AiScriptのメタデータ埋め込み機能を使って、デフォルトとしてプラグインのメタデータを定義する必要があります。 メタデータは次のプロパティを含むオブジェクトです。
|
||||
|
||||
### name
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# Emoji kustom
|
||||
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.
|
||||
カスタム絵文字は、インスタンスで用意された画像を絵文字のように使える機能です。 ノート、リアクション、チャット、自己紹介、名前などの場所で使うことができます。 カスタム絵文字をそれらの場所で使うには、絵文字ピッカーボタン(ある場合)を押すか、`:`を入力して絵文字サジェストを表示します。 テキスト内に`:foo:`のような形式の文字列が見つかると、`foo`の部分がカスタム絵文字名と解釈され、表示時には対応したカスタム絵文字に置き換わります。
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Dek
|
||||
# デッキ
|
||||
|
||||
デッキは利用可能なUIのひとつです。「カラム」と呼ばれるビューを複数並べて表示させることで、カスタマイズ性が高く、情報量の多いUIが構築できることが特徴です。
|
||||
|
||||
|
|
|
@ -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.
|
||||
ユーザーをフォローすると、タイムラインにそのユーザーの投稿が表示されるようになります。ただし、他のユーザーに対する返信は含まれません。 ユーザーをフォローするには、ユーザーページの「フォロー」ボタンをクリックします。フォローを解除するには、もう一度クリックします。
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# キーボードショートカット
|
||||
|
||||
## Global
|
||||
## グローバル
|
||||
これらのショートカットは基本的にどこでも使えます。
|
||||
<table>
|
||||
<thead>
|
||||
|
|
|
@ -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>を参照することはできません。
|
||||
|
|
|
@ -110,7 +110,7 @@ y = Math.floor(pos / mapWidth)
|
|||
```
|
||||
|
||||
### フォームコントロールの種類
|
||||
#### Beralih
|
||||
#### スイッチ
|
||||
type: `switch` スイッチを表示します。何かの機能をオン/オフさせたい場合に有用です。
|
||||
|
||||
##### プロパティ
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
**ストリームでのやり取りはすべてJSONです。**
|
||||
|
||||
## Kanal
|
||||
## チャンネル
|
||||
MisskeyのストリーミングAPIにはチャンネルという概念があります。これは、送受信する情報を分離するための仕組みです。 Misskeyのストリームに接続しただけでは、まだリアルタイムでタイムラインの投稿を受信したりはできません。 ストリーム上でチャンネルに接続することで、様々な情報を受け取ったり情報を送信したりすることができるようになります。
|
||||
|
||||
### チャンネルに接続する
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Tema
|
||||
# テーマ
|
||||
|
||||
テーマを設定して、Misskeyクライアントの見た目を変更できます。
|
||||
|
||||
|
@ -61,8 +61,8 @@
|
|||
* 関数(後述)
|
||||
* `:{関数名}<{引数}<{色}`
|
||||
|
||||
#### Konstanta
|
||||
#### 定数
|
||||
「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。 キー名を`$`で始めると、そのキーはCSS変数として出力されません。
|
||||
|
||||
#### Fungsi
|
||||
#### 関数
|
||||
wip
|
||||
|
|
|
@ -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"
|
||||
## グローバル
|
||||
全てのローカルユーザーの「ホーム」指定されていない投稿と、サーバーに届いた全てのリモートユーザーの「ホーム」指定されていない投稿
|
||||
|
|
|
@ -7,11 +7,11 @@ API를 사용하려면 먼저 액세스 토큰을 취득해야 합니다. 이
|
|||
## 액세스 토큰 가져오기
|
||||
기본적으로 API는 요청 시에 액세스 토큰이 필요합니다. API에 요청하는 것이 자기 자신인지, 불특정한 유저에게 사용하는 애플리케이션인지에 따라 취득 절차가 달라집니다.
|
||||
|
||||
* 전자의 경우: [「자기 자신의 액세스 토큰을 수동으로 발급하기」](#自分自身のアクセストークンを手動発行する)로 진행
|
||||
* 전자의 경우: [ 「자기 자신의 액세스 토큰을 수동으로 발급하기」](#自分自身のアクセストークンを手動発行する)로 진행
|
||||
* 후자의 경우: [「애플리케이션 사용자에게 액세스 토큰 발급을 요청하기」](#アプリケーション利用者にアクセストークンの発行をリクエストする)로 진행
|
||||
|
||||
### 자기 자신의 액세스 토큰을 수동으로 발급하기
|
||||
「설정 > API」에서 자신의 액세스 토큰을 발급할 수 있습니다.
|
||||
「설정 > API」에서 자신의 액세스 토큰을 발급할 수 있습니다.
|
||||
|
||||
[「API 사용 방법」으로 이동](#APIの使い方)
|
||||
|
||||
|
|
|
@ -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)에서 확인할 수 있습니다.
|
||||
|
|
|
@ -8,7 +8,7 @@ Wpisy użytkowników, których obserwujesz
|
|||
## Lokalne
|
||||
全てのローカルユーザーの「ホーム」指定されていない投稿
|
||||
|
||||
## Społeczność
|
||||
## ソーシャル
|
||||
自分のフォローしているユーザーの投稿と、全てのローカルユーザーの「ホーム」指定されていない投稿
|
||||
|
||||
## Globalne
|
||||
|
|
|
@ -93,9 +93,6 @@
|
|||
{ "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"] },
|
||||
|
@ -1222,8 +1219,6 @@
|
|||
{ "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"] },
|
||||
|
|
|
@ -56,8 +56,6 @@ 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
|
@ -55,8 +55,7 @@ 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
|
||||
|
@ -71,14 +70,14 @@ const _https = new https.Agent({
|
|||
* Get http proxy or non-proxy agent
|
||||
*/
|
||||
export const httpAgent = config.proxy
|
||||
? new HttpProxyAgent(config.proxy)
|
||||
? new HttpProxyAgent(config.proxy) as unknown as http.Agent
|
||||
: _http;
|
||||
|
||||
/**
|
||||
* Get https proxy or non-proxy agent
|
||||
*/
|
||||
export const httpsAgent = config.proxy
|
||||
? new HttpsProxyAgent(config.proxy)
|
||||
? new HttpsProxyAgent(config.proxy) as unknown as https.Agent
|
||||
: _https;
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,8 +5,6 @@ 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);
|
||||
|
||||
|
@ -61,12 +59,9 @@ 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,
|
||||
url: emoji.url,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ 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;
|
||||
|
|
|
@ -41,12 +41,14 @@ 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,
|
||||
|
@ -57,6 +59,7 @@ export const packedBlockingSchema = {
|
|||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: 'The blockee.'
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -51,12 +51,14 @@ 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,
|
||||
|
@ -66,6 +68,7 @@ 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,
|
||||
|
|
|
@ -39,12 +39,14 @@ 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,
|
||||
|
@ -59,14 +61,17 @@ 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.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -59,7 +59,6 @@ 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();
|
||||
|
||||
|
@ -70,7 +69,6 @@ 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();
|
||||
|
||||
|
@ -81,7 +79,6 @@ 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();
|
||||
|
||||
|
@ -92,7 +89,6 @@ 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();
|
||||
|
||||
|
@ -154,37 +150,44 @@ 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,
|
||||
|
@ -215,11 +218,13 @@ 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,
|
||||
|
@ -229,22 +234,26 @@ 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'
|
||||
}
|
||||
},
|
||||
|
|
|
@ -59,29 +59,35 @@ 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: {
|
||||
|
|
|
@ -95,12 +95,14 @@ 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,
|
||||
|
@ -111,6 +113,7 @@ 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,
|
||||
|
@ -121,6 +124,7 @@ export const packedFollowingSchema = {
|
|||
type: 'object' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: 'The follower.'
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -34,31 +34,38 @@ 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.'
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -53,12 +53,14 @@ 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,
|
||||
|
|
|
@ -41,12 +41,14 @@ 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,
|
||||
|
@ -57,6 +59,7 @@ export const packedMutingSchema = {
|
|||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: 'The mutee.'
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -35,12 +35,14 @@ 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
Loading…
Reference in New Issue