Merge branch 'develop' into swn

This commit is contained in:
tamaina 2021-08-20 00:30:52 +09:00
commit 1cc5d3e386
752 changed files with 5003 additions and 3570 deletions

View file

@ -1,13 +0,0 @@
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": {
"version": 3,
"proposals": true
}
}
]
]
}

7
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,7 @@
contact_links:
- name: 👪 Misskey Forum
url: https://forum.misskey.io/
about: Ask questions and share knowledge
- name: 💬 Misskey official Discord
url: https://discord.gg/Wp8gVStHW3
about: Chat freely about Misskey

View file

@ -1,21 +1,29 @@
<!-- お読みください <!-- お読みください
PRありがとうございます PRを作成する前に、以下をご確認ください: PRありがとうございます PRを作成する前に、以下をご確認ください:
可能であればタイトルに、以下で示すようなPRの種類が分かるキーワードをプリフィクスしてください。 - 可能であればタイトルに、以下で示すようなPRの種類が分かるキーワードをプリフィクスしてください。
fix / refactor / feat / enhance / perf / chore - fix / refactor / feat / enhance / perf / chore
また、PRの粒度が適切であることを確認してください。ひとつのPRに複数の種類の変更や関心を含めることは避けてください。 - また、PRの粒度が適切であることを確認してください。ひとつのPRに複数の種類の変更や関心を含めることは避けてください。
このPRによって解決されるIssueがある場合は、そのIssue IDを本文内に記入してください。 - このPRによって解決されるIssueがある場合は、そのIssueへの参照を本文内に含めてください。
CHANGELOG.mdに変更点を追記してください。リファクタリングなど、利用者に影響を与えない変更についてはこの限りではありません。 - CHANGELOG.mdに変更点を追記してください。リファクタリングなど、利用者に影響を与えない変更についてはこの限りではありません。
機能追加やバグ修正をした場合は、可能であればテストケースを追加してください。 - この変更により新たに作成、もしくは更新すべきドキュメントがないか確認してください。
- 機能追加やバグ修正をした場合は、可能であればテストケースを追加してください。
- テスト、Lintが通っていることを予め確認してください。
- `npm run test`、`npm run lint`でぞれぞれ実施可能です
- UIに変更がある場合はスクリーンショットを本文内に添付してください。
ご協力ありがとうございます🤗 ご協力ありがとうございます🤗
--> -->
<!-- README <!-- README
Thank you for your PR! Before creating a PR, please check the following: Thank you for your PR! Before creating a PR, please check the following:
If possible, prefix the title with a keyword that identifies the type of this PR, as shown below. - If possible, prefix the title with a keyword that identifies the type of this PR, as shown below.
fix / refactor / feat / enhance / perf / chore - fix / refactor / feat / enhance / perf / chore
Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR. - Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
If there is an issue to be resolved by this PR, please include the Issue ID in the text. - If there is an Issue which will be resolved by this PR, please include a reference to the Issue in the text.
Please add the summary of the changes to CHANGELOG.md. However, this is not necessary for changes that do not affect the users, such as refactoring. - Please add the summary of the changes to CHANGELOG.md. However, this is not necessary for changes that do not affect the users, such as refactoring.
If you have added a feature or fixed a bug, please add a test case if possible. - Check if there are any documents that need to be created or updated due to this change.
- If you have added a feature or fixed a bug, please add a test case if possible.
- Please make sure that tests and Lint are passed in advance.
- You can run it with `npm run test` and `npm run lint`.
- If this PR includes UI changes, please attach a screenshot in the text.
Thanks for your cooperation 🤗 Thanks for your cooperation 🤗
--> -->

11
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

View file

@ -35,6 +35,8 @@ jobs:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Install dependencies - name: Install dependencies
run: yarn install run: yarn install
- name: Check yarn.lock
run: git diff --exit-code yarn.lock
- name: Copy Configure - name: Copy Configure
run: cp .circleci/misskey/*.yml .config run: cp .circleci/misskey/*.yml .config
- name: Build - name: Build

View file

@ -1 +1 @@
v16.2.0 v16.6.2

View file

@ -1,3 +1,56 @@
<!--
## 12.x.x (unreleased)
### Improvements
### Bugfixes
-->
## 12.x.x (unreleased)
### Improvements
- 依存関係の更新
### Bugfixes
- チャンネルを作成しているとアカウントを削除できないのを修正
## 12.88.0 (2021/08/17)
### Features
- ノートの翻訳機能を追加
- 有効にするには、サーバー管理者がDeepLの無料アカウントを登録し、取得した認証キーを「インスタンス設定 > その他 > DeepL Auth Key」に設定する必要があります。
- Misskey更新時にダイアログを表示するように
- ジョブキューウィジェットに警報音を鳴らす設定を追加
### Improvements
- ブロックの挙動を改修
- ブロックされたユーザーがブロックしたユーザーに対してアクション出来ないようになりました。詳細はドキュメントをご確認ください。
- UIデザインの調整
- データベースのインデックスを最適化
- Proxy使用時にKeep-Aliveをサポート
- DNSキャッシュでネガティブキャッシュをサポート
- 依存関係の更新
### Bugfixes
- タッチ操作でウィンドウを閉じることができない問題を修正
- Renoteされた時刻が投稿された時刻のように表示される問題を修正
- コントロールパネルでファイルを削除した際の表示を修正
- ActivityPub: 長いユーザーの名前や自己紹介の対応
## 12.87.0 (2021/08/12)
### Improvements
- 絵文字オートコンプリートで一文字目は最近使った絵文字をサジェストするように
- 絵文字オートコンプリートのパフォーマンスを改善
- about-misskeyページにドキュメントへのリンクを追加
- Docker: Node.jsを16.6.2に
- 依存関係の更新
- 翻訳の更新
### Bugfixes
- Misskey更新時、テーマキャッシュの影響でスタイルがおかしくなる問題を修正
## 12.86.0 (2021/08/11) ## 12.86.0 (2021/08/11)
### Improvements ### Improvements

View file

@ -35,6 +35,11 @@ If your language is not listed in Crowdin, please open an issue.
## Test ## Test
* Test codes are located in [`/test`](/test). * Test codes are located in [`/test`](/test).
### Run specify test
```
npx cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT="./test/tsconfig.json" npx mocha test/foo.ts --require ts-node/register
```
## Continuous integration ## Continuous integration
Misskey uses GitHub Actions for executing automated tests. Misskey uses GitHub Actions for executing automated tests.
Configuration files are located in [`/.github/workflows`](/.github/workflows). Configuration files are located in [`/.github/workflows`](/.github/workflows).

View file

@ -1,4 +1,4 @@
FROM node:16.2.0-alpine3.13 AS base FROM node:16.6.2-alpine3.13 AS base
ENV NODE_ENV=production ENV NODE_ENV=production
@ -18,9 +18,7 @@ RUN apk add --no-cache \
nasm \ nasm \
pkgconfig \ pkgconfig \
python3 \ python3 \
zlib-dev \ zlib-dev
vips-dev \
vips
COPY package.json yarn.lock .yarnrc ./ COPY package.json yarn.lock .yarnrc ./
RUN yarn install RUN yarn install
@ -31,8 +29,7 @@ FROM base AS runner
RUN apk add --no-cache \ RUN apk add --no-cache \
ffmpeg \ ffmpeg \
tini \ tini
vips
ENTRYPOINT ["/sbin/tini", "--"] ENTRYPOINT ["/sbin/tini", "--"]

Binary file not shown.

3
cypress.json Normal file
View file

@ -0,0 +1,3 @@
{
"baseUrl": "http://localhost"
}

View file

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View file

@ -0,0 +1,69 @@
describe('Basic', () => {
before(() => {
cy.request('POST', '/api/reset-db');
});
beforeEach(() => {
cy.reload(true);
});
it('successfully loads', () => {
cy.visit('/');
});
it('setup instance', () => {
cy.visit('/');
cy.get('[data-cy-admin-username] input').type('admin');
cy.get('[data-cy-admin-password] input').type('admin1234');
cy.get('[data-cy-admin-ok]').click();
});
it('signup', () => {
cy.visit('/');
cy.get('[data-cy-signup]').click();
cy.get('[data-cy-signup-username] input').type('alice');
cy.get('[data-cy-signup-password] input').type('alice1234');
cy.get('[data-cy-signup-password-retype] input').type('alice1234');
cy.get('[data-cy-signup-submit]').click();
});
it('signin', () => {
cy.visit('/');
cy.get('[data-cy-signin]').click();
cy.get('[data-cy-signin-username] input').type('alice');
// Enterキーでサインインできるかの確認も兼ねる
cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
});
it('note', () => {
cy.visit('/');
//#region TODO: この辺はUI操作ではなくAPI操作でログインする
cy.get('[data-cy-signin]').click();
cy.get('[data-cy-signin-username] input').type('alice');
// Enterキーでサインインできるかの確認も兼ねる
cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
//#endregion
cy.get('[data-cy-open-post-form]').click();
cy.get('[data-cy-post-form-text]').type('Hello, Misskey!');
cy.get('[data-cy-open-post-form-submit]').click();
// TODO: 投稿した文字列が画面内にあるか(=タイムラインに流れてきたか)のテスト
});
});

22
cypress/plugins/index.js Normal file
View file

@ -0,0 +1,22 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

View file

@ -0,0 +1,25 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

20
cypress/support/index.js Normal file
View file

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

View file

@ -1,3 +1,13 @@
/*
import * as fs from 'fs';
if (fs.existsSync('./built')) {
import('./built/index.js').then(built => built());
} else {
console.log('Built code is not found. Probably an error occurred during a build or you just forgot to build.');
}
*/
const fs = require('fs'); const fs = require('fs');
if (fs.existsSync('./built')) { if (fs.existsSync('./built')) {

View file

@ -1,14 +1,14 @@
--- ---
_lang_: "Deutsch" _lang_: "Deutsch"
headlineMisskey: "Ein durch Notizen verbundenes Netzwerk" headlineMisskey: "Ein durch Notizen verbundenes Netzwerk"
introMisskey: "Willkommen! Misskey ist eine dezentralisierte Open-Source Microblogging-Platform.\nVerfasse \"Notizen\" um mitzuteilen, was gerade passiert oder um Ereignisse mit Anderen zu teilen. 📡\nMit \"Reaktionen\" kannst du außerdem schnell deine Gefühle über Notizen anderer Benutzer zum Ausdruck bringen. 👍\nErforsche eine neue Welt! 🚀" introMisskey: "Willkommen! Misskey ist eine dezentralisierte Open-Source Microblogging-Platform.\nVerfasse „Notizen“ um mitzuteilen, was gerade passiert oder um Ereignisse mit anderen zu teilen. 📡\nMit „Reaktionen“ kannst du außerdem schnell deine Gefühle über Notizen anderer Benutzer zum Ausdruck bringen. 👍\nEine neue Welt wartet auf dich! 🚀"
monthAndDay: "{day}/{month}" monthAndDay: "{day}.{month}."
search: "Suchen" search: "Suchen"
notifications: "Benachrichtigungen" notifications: "Benachrichtigungen"
username: "Benutzername" username: "Benutzername"
password: "Passwort" password: "Passwort"
forgotPassword: "Passwort vergessen" forgotPassword: "Passwort vergessen"
fetchingAsApObject: "Wird aus dem Fediverse angefragt..." fetchingAsApObject: "Wird aus dem Fediverse angefragt"
ok: "OK" ok: "OK"
gotIt: "Verstanden!" gotIt: "Verstanden!"
cancel: "Abbrechen" cancel: "Abbrechen"
@ -25,10 +25,10 @@ profile: "Profil"
timeline: "Chronik" timeline: "Chronik"
noAccountDescription: "Dieser Nutzer hat seine Profilbeschreibung noch nicht ausgefüllt." noAccountDescription: "Dieser Nutzer hat seine Profilbeschreibung noch nicht ausgefüllt."
login: "Anmelden" login: "Anmelden"
loggingIn: "Du wirst angemeldet..." loggingIn: "Du wirst angemeldet"
logout: "Abmelden" logout: "Abmelden"
signup: "Registrieren" signup: "Registrieren"
uploading: "Wird hochgeladen..." uploading: "Wird hochgeladen"
save: "Speichern" save: "Speichern"
users: "Benutzer" users: "Benutzer"
addUser: "Benutzer hinzufügen" addUser: "Benutzer hinzufügen"
@ -63,7 +63,7 @@ import: "Import"
export: "Export" export: "Export"
files: "Dateien" files: "Dateien"
download: "Herunterladen" download: "Herunterladen"
driveFileDeleteConfirm: "Möchtest du die Datei \"{name}\" wirklich löschen? Die zugehörige Notiz wird ebenso verschwinden." driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Die zugehörige Notiz wird ebenso verschwinden."
unfollowConfirm: "Möchtest du {name} nicht mehr folgen?" unfollowConfirm: "Möchtest du {name} nicht mehr folgen?"
exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt." exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt."
importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen." importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen."
@ -80,7 +80,7 @@ error: "Fehler"
somethingHappened: "Ein Fehler ist aufgetreten" somethingHappened: "Ein Fehler ist aufgetreten"
retry: "Wiederholen" retry: "Wiederholen"
pageLoadError: "Laden der Seite fehlgeschlagen." pageLoadError: "Laden der Seite fehlgeschlagen."
pageLoadErrorDescription: "Dieser Fehler wird meist durch Netzwerkfehler oder den Browser-Cache verursacht. Versuche bitte den Browser-Cache zu leeren und es nach kurzer Zeit noch einmal zu probieren." pageLoadErrorDescription: "Dieser Fehler wird meist durch Netzwerkfehler oder den Browser-Cache verursacht. Bitte leere den Cache oder versuche es nach einiger Zeit erneut."
enterListName: "Name der Liste eingeben" enterListName: "Name der Liste eingeben"
privacy: "Privatsphäre" privacy: "Privatsphäre"
makeFollowManuallyApprove: "Follow-Anfragen benötigen Bestätigung" makeFollowManuallyApprove: "Follow-Anfragen benötigen Bestätigung"
@ -105,7 +105,7 @@ sensitive: "NSFW"
add: "Hinzufügen" add: "Hinzufügen"
reaction: "Reaktionen" reaction: "Reaktionen"
reactionSettingDescription: "Wähle die Reaktionen aus, die in der Reaktionsauswahl angezeigt werden sollen." reactionSettingDescription: "Wähle die Reaktionen aus, die in der Reaktionsauswahl angezeigt werden sollen."
reactionSettingDescription2: "Ziehe zum Anordnen, Klicke zum Löschen, Drücke \"+\" zum Hinzufügen" reactionSettingDescription2: "Ziehe zum Anordnen, klicke zum Löschen, drücke + zum Hinzufügen"
rememberNoteVisibility: "Notizsichtbarkeit merken" rememberNoteVisibility: "Notizsichtbarkeit merken"
attachCancel: "Anhang entfernen" attachCancel: "Anhang entfernen"
markAsSensitive: "Als NSFW markieren" markAsSensitive: "Als NSFW markieren"
@ -129,14 +129,14 @@ editWidgetsExit: "Fertig"
customEmojis: "Benutzerdefinierte Emojis" customEmojis: "Benutzerdefinierte Emojis"
emoji: "Emojis" emoji: "Emojis"
emojis: "Emojis" emojis: "Emojis"
emojiName: "Emojiname" emojiName: "Emoji-Name"
emojiUrl: "Emoji-URL" emojiUrl: "Emoji-URL"
addEmoji: "Emoji hinzufügen" addEmoji: "Emoji hinzufügen"
settingGuide: "Empfohlene Einstellung" settingGuide: "Empfohlene Einstellung"
cacheRemoteFiles: "Dateien von fremden Instanzen im Cache speichern" cacheRemoteFiles: "Dateien von fremden Instanzen im Cache speichern"
cacheRemoteFilesDescription: "Ist diese Einstellung deaktiviert, so werden Dateien fremder Instanzen direkt von dort geladen. Hierdurch wird Speicherplatz auf dem Server gespart, aber durch fehlende Generierung von Vorschaubildern mehr Bandbreite verwendet." cacheRemoteFilesDescription: "Ist diese Einstellung deaktiviert, so werden Dateien fremder Instanzen direkt von dort geladen. Hierdurch wird Speicherplatz auf dem Server gespart, aber durch fehlende Generierung von Vorschaubildern mehr Bandbreite verwendet."
flagAsBot: "Als Bot markieren" flagAsBot: "Als Bot markieren"
flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskey's interne Systeme dieses Benutzerkonto als Bot behandeln." flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskeys interne Systeme dieses Benutzerkonto als Bot behandeln."
flagAsCat: "Als Katze markieren" flagAsCat: "Als Katze markieren"
flagAsCatDescription: "Aktiviere diese Option, um dieses Benutzerkonto als Katze zu markieren." flagAsCatDescription: "Aktiviere diese Option, um dieses Benutzerkonto als Katze zu markieren."
autoAcceptFollowed: "Follow-Anfragen von Benutzern, denen du folgst, automatisch akzeptieren" autoAcceptFollowed: "Follow-Anfragen von Benutzern, denen du folgst, automatisch akzeptieren"
@ -196,7 +196,7 @@ noteDeleteConfirm: "Möchtest du diese Notiz wirklich löschen?"
pinLimitExceeded: "Es können nicht noch mehr Notizen angeheftet werden" pinLimitExceeded: "Es können nicht noch mehr Notizen angeheftet werden"
intro: "Misskey Installation abgeschlossen! Lass uns nun ein Administratorkonto erstellen." intro: "Misskey Installation abgeschlossen! Lass uns nun ein Administratorkonto erstellen."
done: "Fertig" done: "Fertig"
processing: "In Bearbeitung..." processing: "In Bearbeitung"
preview: "Vorschau" preview: "Vorschau"
default: "Standard" default: "Standard"
noCustomEmojis: "Keine benutzerdefinierten Emojis vorhanden" noCustomEmojis: "Keine benutzerdefinierten Emojis vorhanden"
@ -227,8 +227,8 @@ announcements: "Ankündigungen"
imageUrl: "Bild-URL" imageUrl: "Bild-URL"
remove: "Löschen" remove: "Löschen"
removed: "Erfolgreich gelöscht" removed: "Erfolgreich gelöscht"
removeAreYouSure: "Möchtest du \"{x}\" wirklich entfernen?" removeAreYouSure: "Möchtest du „{x}“ wirklich entfernen?"
deleteAreYouSure: "Möchtest du \"{x}\" wirklich löschen?" deleteAreYouSure: "Möchtest du „{x}“ wirklich löschen?"
resetAreYouSure: "Wirklich zurücksetzen?" resetAreYouSure: "Wirklich zurücksetzen?"
saved: "Gespeichert" saved: "Gespeichert"
messaging: "Chat" messaging: "Chat"
@ -240,7 +240,7 @@ uploadFromUrlDescription: "URL der hochzuladenden Datei"
uploadFromUrlRequested: "Upload angefordert" uploadFromUrlRequested: "Upload angefordert"
uploadFromUrlMayTakeTime: "Es kann eine Weile dauern, bis das Hochladen abgeschlossen ist." uploadFromUrlMayTakeTime: "Es kann eine Weile dauern, bis das Hochladen abgeschlossen ist."
explore: "Erkunden" explore: "Erkunden"
games: "Misskey Spiele" games: "Misskey-Spiele"
messageRead: "Gelesen" messageRead: "Gelesen"
noMoreHistory: "Kein weiterer Verlauf vorhanden" noMoreHistory: "Kein weiterer Verlauf vorhanden"
startMessaging: "Neuen Chat erstellen" startMessaging: "Neuen Chat erstellen"
@ -256,14 +256,14 @@ birthday: "Geburtstag"
yearsOld: "{age} Jahre alt" yearsOld: "{age} Jahre alt"
registeredDate: "Registrationsdatum" registeredDate: "Registrationsdatum"
location: "Ort" location: "Ort"
theme: "Farbthemen" theme: "Farbschema"
themeForLightMode: "Farbthema, das im Hellmodus genutzt wird" themeForLightMode: "Helles Farbschema"
themeForDarkMode: "Farbthema, das im Dunkelmodus genutzt wird" themeForDarkMode: "Dunkles Farbschema"
light: "Hell" light: "Hell"
dark: "Dunkel" dark: "Dunkel"
lightThemes: "Helle Farbthemen" lightThemes: "Helle Farbschemata"
darkThemes: "Dunkle Farbthemen" darkThemes: "Dunkle Farbschemata"
syncDeviceDarkMode: "Dunkelmodus mit den Einstellungen deines Gerätes synchronisieren" syncDeviceDarkMode: "Einstellung deines Geräts übernehmen"
drive: "Drive" drive: "Drive"
fileName: "Dateiname" fileName: "Dateiname"
selectFile: "Datei auswählen" selectFile: "Datei auswählen"
@ -293,7 +293,7 @@ whenServerDisconnected: "Bei Verbindungsverlust zum Server"
disconnectedFromServer: "Verbindung zum Server wurde getrennt" disconnectedFromServer: "Verbindung zum Server wurde getrennt"
reload: "Aktualisieren" reload: "Aktualisieren"
doNothing: "Ignorieren" doNothing: "Ignorieren"
reloadConfirm: "Möchtest du die Chronik aktualisieren?" reloadConfirm: "Seite neu laden?"
watch: "Beobachten" watch: "Beobachten"
unwatch: "Nicht mehr beobachten" unwatch: "Nicht mehr beobachten"
accept: "Akzeptieren" accept: "Akzeptieren"
@ -302,10 +302,10 @@ normal: "Normal"
instanceName: "Name der Instanz" instanceName: "Name der Instanz"
instanceDescription: "Beschreibung der Instanz" instanceDescription: "Beschreibung der Instanz"
maintainerName: "Betreiber" maintainerName: "Betreiber"
maintainerEmail: "Betreiber-Email" maintainerEmail: "Betreiber-E-Mail"
tosUrl: "URL der Nutzungsbedingungen" tosUrl: "URL der Nutzungsbedingungen"
thisYear: "Dieses Jahr" thisYear: "Jahr"
thisMonth: "Dieser Monat" thisMonth: "Monat"
today: "Heute" today: "Heute"
dayX: "{day}" dayX: "{day}"
monthX: "{month}" monthX: "{month}"
@ -522,7 +522,7 @@ scratchpadDescription: "Die Testumgebung bietet eine Umgebung für AiScript-Expe
output: "Ausgabe" output: "Ausgabe"
script: "Skript" script: "Skript"
disablePagesScript: "AiScript auf Seiten deaktivieren" disablePagesScript: "AiScript auf Seiten deaktivieren"
updateRemoteUser: "Informationen über Benutzer fremder Instanzen aktualisieren" updateRemoteUser: "Benutzerinformationen aktualisieren"
deleteAllFiles: "Alle Dateien löschen" deleteAllFiles: "Alle Dateien löschen"
deleteAllFilesConfirm: "Möchtest du wirklich alle Dateien löschen?" deleteAllFilesConfirm: "Möchtest du wirklich alle Dateien löschen?"
removeAllFollowing: "Allen gefolgten Benutzern entfolgen" removeAllFollowing: "Allen gefolgten Benutzern entfolgen"
@ -715,7 +715,7 @@ inChannelSearch: "In Kanal suchen"
useReactionPickerForContextMenu: "Reaktionsauswahl durch Rechtsklick öffnen" useReactionPickerForContextMenu: "Reaktionsauswahl durch Rechtsklick öffnen"
typingUsers: "{users} ist/sind am schreiben..." typingUsers: "{users} ist/sind am schreiben..."
jumpToSpecifiedDate: "Zu bestimmtem Datum springen" jumpToSpecifiedDate: "Zu bestimmtem Datum springen"
showingPastTimeline: "Momentan wird eine alte Chronik angezeigt" showingPastTimeline: "Es wird eine alte Chronik angezeigt"
clear: "Zurückkehren" clear: "Zurückkehren"
markAllAsRead: "Alle als gelesen markieren" markAllAsRead: "Alle als gelesen markieren"
goBack: "Zurück" goBack: "Zurück"
@ -771,6 +771,12 @@ received: "Erhalten"
searchResult: "Suchergebnisse" searchResult: "Suchergebnisse"
hashtags: "Hashtags" hashtags: "Hashtags"
troubleshooting: "Problembehandlung" troubleshooting: "Problembehandlung"
useBlurEffect: "Weichzeichnungseffekt in der Benutzeroberfläche verwenden"
learnMore: "Mehr erfahren"
misskeyUpdated: "Misskey wurde aktualisiert!"
whatIsNew: "Änderungen anzeigen"
translate: "Übersetzen"
translatedFrom: "Aus {x} übersetzt"
_docs: _docs:
continueReading: "Mehr lesen" continueReading: "Mehr lesen"
features: "Funktionen" features: "Funktionen"
@ -792,7 +798,7 @@ _gallery:
unlike: "\"Gefällt mir\" entfernen" unlike: "\"Gefällt mir\" entfernen"
_email: _email:
_follow: _follow:
title: "ist dir gefolgt" title: "Du hast einen neuen Follower"
_receiveFollowRequest: _receiveFollowRequest:
title: "Du hast eine Follow-Anfrage erhalten" title: "Du hast eine Follow-Anfrage erhalten"
_plugin: _plugin:
@ -1046,7 +1052,7 @@ _time:
_tutorial: _tutorial:
title: "Wie du Misskey verwendest" title: "Wie du Misskey verwendest"
step1_1: "Willkommen!" step1_1: "Willkommen!"
step1_2: "Diese Seite ist die \"Chronik\". Sie zeigt dir deine geschrieben \"Notizen\" sowie die aller Benutzer, denen du \"folgst\", in chronologischer Reihenfolge." step1_2: "Diese Seite ist die „Chronik“. Sie zeigt dir deine geschrieben „Notizen“ sowie die aller Benutzer, denen du „folgst“, in chronologischer Reihenfolge."
step1_3: "Deine Chronik sollte momentan leer sein, da du bis jetzt noch keine Notizen geschrieben hast und auch noch keinen Benutzern folgst." step1_3: "Deine Chronik sollte momentan leer sein, da du bis jetzt noch keine Notizen geschrieben hast und auch noch keinen Benutzern folgst."
step2_1: "Lass uns zuerst dein Profil vervollständigen, bevor du Notizen schreibst oder jemandem folgst." step2_1: "Lass uns zuerst dein Profil vervollständigen, bevor du Notizen schreibst oder jemandem folgst."
step2_2: "Informationen darüber, was für eine Person du bist, macht es anderen leichter zu wissen, ob sie deine Notizen sehen wollen und ob sie dir folgen möchten." step2_2: "Informationen darüber, was für eine Person du bist, macht es anderen leichter zu wissen, ob sie deine Notizen sehen wollen und ob sie dir folgen möchten."
@ -1055,7 +1061,7 @@ _tutorial:
step3_3: "Fülle das Fenster aus und drücke auf den Knopf oben rechts zum Senden." step3_3: "Fülle das Fenster aus und drücke auf den Knopf oben rechts zum Senden."
step3_4: "Fällt dir nichts ein, das du schreiben möchtest? Versuch's mit \"Hallo Misskey!\"" step3_4: "Fällt dir nichts ein, das du schreiben möchtest? Versuch's mit \"Hallo Misskey!\""
step4_1: "Fertig mit dem Senden deiner ersten Notiz?" step4_1: "Fertig mit dem Senden deiner ersten Notiz?"
step4_2: "Falls deine Notiz nun auf deiner Chronik auftaucht, hast du alles richtig gemacht." step4_2: "Falls deine Notiz nun in deiner Chronik auftaucht, hast du alles richtig gemacht."
step5_1: "Lass uns nun deiner Chronik etwas mehr Leben einhauchen, indem du einigen anderen Benutzern folgst." step5_1: "Lass uns nun deiner Chronik etwas mehr Leben einhauchen, indem du einigen anderen Benutzern folgst."
step5_2: "{featured} zeigt dir beliebte Notizen dieser Instanz. In {explore} kannst du beliebte Benutzer finden. Schau dort, ob du Benutzer findest, die dich interessieren." step5_2: "{featured} zeigt dir beliebte Notizen dieser Instanz. In {explore} kannst du beliebte Benutzer finden. Schau dort, ob du Benutzer findest, die dich interessieren."
step5_3: "Klicke zum Anzeigen des Profils eines Benutzers auf dessen Profilbild und dann auf den \"Folgen\"-Knopf, um diesem zu folgen." step5_3: "Klicke zum Anzeigen des Profils eines Benutzers auf dessen Profilbild und dann auf den \"Folgen\"-Knopf, um diesem zu folgen."

View file

@ -249,7 +249,7 @@ agreeTo: "I agree to {0}"
tos: "Terms of Service" tos: "Terms of Service"
start: "Begin" start: "Begin"
home: "Home" home: "Home"
remoteUserCaution: "As this user is from a renote instance, the shown information may be incomplete." remoteUserCaution: "As this user is from a remote instance, the shown information may be incomplete."
activity: "Activity" activity: "Activity"
images: "Images" images: "Images"
birthday: "Birthday" birthday: "Birthday"
@ -771,6 +771,12 @@ received: "Received"
searchResult: "Search results" searchResult: "Search results"
hashtags: "Hashtags" hashtags: "Hashtags"
troubleshooting: "Troubleshooting" troubleshooting: "Troubleshooting"
useBlurEffect: "Use blur effects in the UI"
learnMore: "Learn more"
misskeyUpdated: "Misskey has been updated!"
whatIsNew: "Show changes"
translate: "Translate"
translatedFrom: "Translated from {x}"
_docs: _docs:
continueReading: "Read more" continueReading: "Read more"
features: "Features" features: "Features"

View file

@ -1,7 +1,7 @@
--- ---
_lang_: "Esperanto" _lang_: "Esperanto"
headlineMisskey: "Reto liganta per notoj" headlineMisskey: "Reto ligata per notoj"
introMisskey: "Bonvenon! Misskey estas malfermitkoda malcentriza mikrobloga servo.\nKreu \"noto\"n por kunhavu tion ke nun okazas, aŭ por dissendu pri vi📡\nPer la funkcio \"reago\" vi ankaŭ povas rapide esprimi vian senton pri ĉies noto👍\nVolu esplori nova mondo🚀" introMisskey: "Bonvenon! Misskey estas malfermitkoda malcentraliza mikrobloga servo.\nKreu \"noto\"n por diskonigi tion ke nun okazas, aŭ por dissendu pri vi📡\nPer la funkcio \"reago\" vi ankaŭ povas rapide esprimi vian senton pri ĉies noto👍\nVolu esplori nova mondo🚀"
monthAndDay: "{day}-a/{month}" monthAndDay: "{day}-a/{month}"
search: "Serĉi" search: "Serĉi"
notifications: "Sciigoj" notifications: "Sciigoj"
@ -10,10 +10,10 @@ password: "Pasvorto"
forgotPassword: "Ĉu vi forgesis pasvorton?" forgotPassword: "Ĉu vi forgesis pasvorton?"
fetchingAsApObject: "Informpetado de Fediverso..." fetchingAsApObject: "Informpetado de Fediverso..."
ok: "Akcepteble" ok: "Akcepteble"
gotIt: "Mi konprenas!" gotIt: "Mi komprenas"
cancel: "Nuligi" cancel: "Nuligi"
enterUsername: "Entajpu uzantnomon" enterUsername: "Entajpu uzantnomon"
renotedBy: "Renoton faras {user}" renotedBy: "Renoto farita de {user}"
noNotes: "Neniu noto!" noNotes: "Neniu noto!"
noNotifications: "Vi ne havas sciigojn." noNotifications: "Vi ne havas sciigojn."
instance: "Ekzemplo" instance: "Ekzemplo"
@ -44,7 +44,7 @@ copyContent: "Kopii enhavon"
copyLink: "Kopii ligilon" copyLink: "Kopii ligilon"
delete: "Forviŝi" delete: "Forviŝi"
deleteAndEdit: "Forigi kaj redakti" deleteAndEdit: "Forigi kaj redakti"
deleteAndEditConfirm: "Ĉu vi certas, ke vi volas forigi kaj redakti la noton? Ĉiuj reagoj, renotoj, kaj respondoj ankaŭ foriĝos." deleteAndEditConfirm: "Ĉu vi certas, ke vi volas forigi kaj redakti la noton? Ankaŭ ĉiuj reagoj, renotoj, kaj respondoj al ĝi foriĝos."
addToList: "Aldoni al la listo" addToList: "Aldoni al la listo"
sendMessage: "Sendi mesaĝon" sendMessage: "Sendi mesaĝon"
copyUsername: "Kopii uzantnomon" copyUsername: "Kopii uzantnomon"
@ -52,12 +52,13 @@ searchUser: "Serĉi uzanton"
reply: "Respondi" reply: "Respondi"
loadMore: "Vidu pli" loadMore: "Vidu pli"
showMore: "Vidi pli" showMore: "Vidi pli"
youGotNewFollower: "Vin eksekvis" youGotNewFollower: "sksekvis vin"
receiveFollowRequest: "Eksekvopeton riceviĝis." receiveFollowRequest: "Peto de sekvado estas ricevita"
followRequestAccepted: "La eksekvopeto akceptiĝis." followRequestAccepted: "La peto de sekvado akceptita"
mention: "Mencioj" mention: "Mencioj"
mentions: "Al vi" mentions: "Al vi"
importAndExport: "Importaĵo / Eksportaĵo" directNotes: "Rektaj notoj"
importAndExport: "Importi/eksporti"
import: "Importi" import: "Importi"
export: "Eksporti" export: "Eksporti"
files: "Dosieroj" files: "Dosieroj"
@ -70,7 +71,7 @@ note: "Elsendi noto"
notes: "Notoj" notes: "Notoj"
following: "Sekvatoj" following: "Sekvatoj"
followers: "Sekvantoj" followers: "Sekvantoj"
followsYou: "Vin sekvas " followsYou: "Sekvas vin"
createList: "Kreii liston" createList: "Kreii liston"
error: "Eraro" error: "Eraro"
somethingHappened: "Problemo okazis." somethingHappened: "Problemo okazis."
@ -78,9 +79,9 @@ retry: "Reprovi"
enterListName: "Entajpu nomon de la listo" enterListName: "Entajpu nomon de la listo"
privacy: "Privateco" privacy: "Privateco"
follow: "Sekvi" follow: "Sekvi"
followRequest: "Peti akcepti de vi eksekvi" followRequest: "Peti de sekvado"
followRequests: "Eksekvopetoj" followRequests: "Petoj de sekvado"
unfollow: "Ne plu sekvi" unfollow: "Malsekvi"
enterEmoji: "Entajpu emoĵion" enterEmoji: "Entajpu emoĵion"
renote: "Fari renoton" renote: "Fari renoton"
unrenote: "Malfari renoton" unrenote: "Malfari renoton"
@ -95,7 +96,7 @@ clickToShow: "Klaku por malkaŝu"
sensitive: "Enhavo ne estas deca por laborejo (NSFW)" sensitive: "Enhavo ne estas deca por laborejo (NSFW)"
add: "Aldoni" add: "Aldoni"
reaction: "Reagoj" reaction: "Reagoj"
enterFileName: "Entajpu dosiernomon" enterFileName: "Entajpu nomon de dosiero"
mute: "Silentigi" mute: "Silentigi"
unmute: "Malsilentigi" unmute: "Malsilentigi"
block: "Bloki" block: "Bloki"
@ -115,7 +116,7 @@ customEmojis: "Personecigitaj emoĵioj"
emoji: "Emoĵio" emoji: "Emoĵio"
emojis: "Emoĵio" emojis: "Emoĵio"
emojiName: "Nomo de emoĵio" emojiName: "Nomo de emoĵio"
emojiUrl: "URL de la bildo de emoĵio" emojiUrl: "URL de la emoĵio"
addEmoji: "Aldoni emoĵion" addEmoji: "Aldoni emoĵion"
settingGuide: "Rekomendaj agordoj" settingGuide: "Rekomendaj agordoj"
cacheRemoteFiles: "Havi staplon por transaj dosieroj" cacheRemoteFiles: "Havi staplon por transaj dosieroj"
@ -124,16 +125,20 @@ flagAsCat: "Tiu uzanto estas kato"
addAccount: "Aldoni konton" addAccount: "Aldoni konton"
showOnRemote: "Vidi sur la fora ekzemplo" showOnRemote: "Vidi sur la fora ekzemplo"
general: "Ĝenerala" general: "Ĝenerala"
wallpaper: "Ekranfonoj"
setWallpaper: "Apliki ekranfonon"
removeWallpaper: "Forviŝi ekranfonon. "
searchWith: "Serĉi: {q}" searchWith: "Serĉi: {q}"
youHaveNoLists: "Vi ne havas listojn." youHaveNoLists: "Vi ne havas listojn."
followConfirm: "Ĉu vi certas ke vi volas sekvi {name}'(o)n?" followConfirm: "Ĉu vi certas ke vi volas sekvi {name}'(o)n?"
selectUser: "Elekti uzanton" selectUser: "Elekti uzanton"
annotation: "Komentarioj" annotation: "Komentarioj"
federation: "Konfederacio" federation: "Kunfederaĵo"
instances: "Ekzemplo" instances: "Ekzemplo"
perHour: "Po horo" perHour: "Po horo"
perDay: "Po tago" perDay: "Po tago"
blockThisInstance: "Bloki tiu ekzemplo" blockThisInstance: "Bloki tiu ekzemplo"
version: "Versio"
withNFiles: "{n} dosiero(j)" withNFiles: "{n} dosiero(j)"
disk: "Diskilo" disk: "Diskilo"
instanceInfo: "Informo pri la ekzemplo" instanceInfo: "Informo pri la ekzemplo"
@ -147,61 +152,86 @@ noUsers: "Sen uzantoj"
editProfile: "Redakti profilon" editProfile: "Redakti profilon"
noteDeleteConfirm: "Ĉu vi certas ke vi volas forviŝi la noton?" noteDeleteConfirm: "Ĉu vi certas ke vi volas forviŝi la noton?"
pinLimitExceeded: "Vi ne plu povas alpingli noton." pinLimitExceeded: "Vi ne plu povas alpingli noton."
processing: "Traktado..."
noCustomEmojis: "Neniu emoĵio" noCustomEmojis: "Neniu emoĵio"
federating: "Konfederado" federating: "Kunfederado"
blocked: "Blokata" blocked: "Blokata"
all: "Ĉiuj"
subscribing: "Abonita" subscribing: "Abonita"
publishing: "Dissendado"
notResponding: "Alvokato ne disponeblas" notResponding: "Alvokato ne disponeblas"
instanceFollowing: "Sekvatoj sur la ekzemplo" instanceFollowing: "Sekvatoj el la ekzemplo"
instanceFollowers: "Sekvantoj el la ekzemplo" instanceFollowers: "Sekvantoj el la ekzemplo"
instanceUsers: "Uzantoj de la ekzemplo" instanceUsers: "Uzantoj de la ekzemplo"
changePassword: "Ŝanĝi pasvorton" changePassword: "Ŝanĝi pasvorton"
security: "Sekureco"
currentPassword: "Aktuala pasvorto" currentPassword: "Aktuala pasvorto"
newPassword: "Nova pasvorto" newPassword: "Nova pasvorto"
newPasswordRetype: "Reentajpu la novan pasvorton" newPasswordRetype: "Reentajpu la novan pasvorton"
attachFile: "Aldoni dosieron" attachFile: "Aldoni dosieron"
more: "Plu!" more: "Plu!"
featured: "Maksimumi"
usernameOrUserId: "Uzantnomo aŭ identigilo de uzanto" usernameOrUserId: "Uzantnomo aŭ identigilo de uzanto"
noSuchUser: "Neniuj uzantoj trovitaj." noSuchUser: "Neniuj uzantoj trovitaj."
lookup: "Informpeti"
announcements: "Novaĵoj"
imageUrl: "URL de bildo" imageUrl: "URL de bildo"
remove: "Forigi" remove: "Forigi"
removed: "Forviŝis" removed: "Forviŝis"
removeAreYouSure: "Ĉu vi certas ke vi volas forigi \"{x}\"'(o)n?" removeAreYouSure: "Ĉu vi certas ke vi volas forigi \"{x}\"'(o)n?"
deleteAreYouSure: "Ĉu vi certas ke vi volas forviŝi \"{x}\"'(o)n?" deleteAreYouSure: "Ĉu vi certas ke vi volas forviŝi \"{x}\"'(o)n?"
saved: "Konservita"
messaging: "Retbabili" messaging: "Retbabili"
upload: "Alŝuti" upload: "Alŝuti"
fromDrive: "De la diskingo" fromDrive: "De la disko"
fromUrl: "De URL" fromUrl: "De URL"
uploadFromUrl: "Alŝuti de URL" uploadFromUrl: "Alŝuti de URL"
uploadFromUrlDescription: "URL de la dosiero kiun vi volu alŝuti" uploadFromUrlDescription: "URL de la dosiero kiun vi volas alŝuti"
explore: "Esplori"
games: "Ludoj sur Misskey" games: "Ludoj sur Misskey"
messageRead: "Legita" messageRead: "Legita"
startMessaging: "Komenci babiladon" startMessaging: "Komenci babiladon"
nUsersRead: "Legita de {n} homoj"
tos: "Kondiĉoj de uzado" tos: "Kondiĉoj de uzado"
start: "Komenciĝi" start: "Komenciĝi"
home: "Hejmo" home: "Hejmo"
remoteUserCaution: "Ĉi tiu Infomoj estas ne tute ekzakta pro distanca uzanto." remoteUserCaution: "Ĉi tiu Infomoj estas ne tute ekzakta pro distanca uzanto."
activity: "Aktiveco"
images: "Bildoj" images: "Bildoj"
birthday: "Naskiĝtago" birthday: "Naskiĝdato"
registeredDate: "Registriĝdato" registeredDate: "Registriĝdato"
drive: "Diskingo" location: "Loko"
theme: "Koloraro"
light: "Luma"
dark: "Malluma"
drive: "Disko"
fileName: "Dosiernomo" fileName: "Dosiernomo"
selectFile: "Elekti dosieron" selectFile: "Elekti dosieron"
selectFiles: "Elekti dosieron" selectFiles: "Elekti dosieron"
selectFolder: "Elekti dosierujon"
selectFolders: "Elekti dosierujon"
renameFile: "Alinomi la dosieron" renameFile: "Alinomi la dosieron"
folderName: "Nomo de la dosierujo" folderName: "Nomo de la dosierujo"
createFolder: "Krei dosierujon"
renameFolder: "Alinomi la dosierujon" renameFolder: "Alinomi la dosierujon"
deleteFolder: "Forviŝi dosierujon" deleteFolder: "Forviŝi dosierujon"
addFile: "Aldoni dosieron" addFile: "Aldoni dosieron"
emptyDrive: "La diskingo malplenas." emptyDrive: "La disko malplenas"
emptyFolder: "La dosierujo malplenas"
unableToDelete: "Ne forigebla" unableToDelete: "Ne forigebla"
inputNewFileName: "Entajpu nova dosiernomon" inputNewFileName: "Entajpu nova nomon de la dosiero"
inputNewFolderName: "Entajpu nova nomon de la dosierujo" inputNewFolderName: "Entajpu nova nomon de la dosierujo"
hasChildFilesOrFolders: "La dosierujo ne estas forviŝebla, ĉar ĝi ne malplenas." hasChildFilesOrFolders: "La dosierujo ne estas forviŝebla, ĉar ĝi ne malplenas."
copyUrl: "Kopii URL" copyUrl: "Kopii URL"
rename: "Alinomi" rename: "Alinomi"
avatar: "Ikono" avatar: "Ikono"
banner: "Standardo"
nsfw: "Enhavo ne estas deca por laborejo (NSFW)" nsfw: "Enhavo ne estas deca por laborejo (NSFW)"
reload: "Reŝargi"
watch: "Observi"
unwatch: "Malobservi"
accept: "Permesi"
normal: "Normala"
instanceName: "Nomo de la ekzemplo" instanceName: "Nomo de la ekzemplo"
maintainerName: "Nomo de la administranto" maintainerName: "Nomo de la administranto"
maintainerEmail: "Retpoŝto de la administranto" maintainerEmail: "Retpoŝto de la administranto"
@ -212,15 +242,24 @@ today: "Hodiaŭ"
dayX: "{day}-a" dayX: "{day}-a"
monthX: "{month}" monthX: "{month}"
yearX: "La jaro {year}" yearX: "La jaro {year}"
pages: "Paĝoj"
connectService: "Konekti" connectService: "Konekti"
disconnectService: "Farkonektiĝi" disconnectService: "Farkonektiĝi"
driveCapacityPerLocalAccount: "Volumo de miskej-diskingo po unu loka uzanto" enableGlobalTimeline: "Ebligi mallokan templinion"
driveCapacityPerRemoteAccount: "Volumo de miskej-diskingo po unu transa uzanto" registration: "Registri"
iconUrl: "URL de la ikono (retpaĝsimbolo, ktp.)" driveCapacityPerLocalAccount: "Volumo de disko po unu loka uzanto"
driveCapacityPerRemoteAccount: "Volumo de disko po unu transa uzanto"
iconUrl: "URL de la ikono (retpaĝsimbolo, ktp)"
bannerUrl: "URL de standardo"
backgroundImageUrl: "URL de fona bildo"
basicInfo: "Baza informo"
pinnedUsers: "Alpinglita uzanto" pinnedUsers: "Alpinglita uzanto"
pinnedPages: "Alpinglitaj paĝoj"
pinnedNotes: "Pinglita noto" pinnedNotes: "Pinglita noto"
antennas: "Antenoj"
name: "Nomo" name: "Nomo"
withFileAntenna: "Nur kun aldonaĵo" withFileAntenna: "Nur kun aldonaĵo"
withReplies: "Inkluzive respondoj"
notesAndReplies: "Kun respondoj" notesAndReplies: "Kun respondoj"
withFiles: "Kun aldonaĵo" withFiles: "Kun aldonaĵo"
silence: "Mutigi" silence: "Mutigi"
@ -231,53 +270,98 @@ recentlyUpdatedUsers: "Uzantoj kiu lastatempe faris noton"
recentlyRegisteredUsers: "Nove aniĝintaj uzantoj" recentlyRegisteredUsers: "Nove aniĝintaj uzantoj"
popularTags: "Popularaj kradvortoj" popularTags: "Popularaj kradvortoj"
userList: "Listoj" userList: "Listoj"
about: "Informoj"
aboutMisskey: "Pri Misskey" aboutMisskey: "Pri Misskey"
administrator: "Administranto"
moderator: "Moderigisto"
securityKey: "Sekureca ŝlosilo"
securityKeyName: "Nomo de la ŝlosilo" securityKeyName: "Nomo de la ŝlosilo"
lastUsed: "Plej malnove uzita"
passwordLessLogin: "Ensaluti sen pasvorto" passwordLessLogin: "Ensaluti sen pasvorto"
resetPassword: "Restarigi pasvorton" resetPassword: "Restarigi pasvorton"
newPasswordIs: "La nova pasvorto estas {password}." newPasswordIs: "La nova pasvorto estas {password}."
share: "Diskonigi"
notFound: "Ne trovita"
cacheClear: "Malplenigi staplon" cacheClear: "Malplenigi staplon"
help: "Manlibro de uzado" help: "Manlibro de uzado"
inputMessageHere: "Entajpu masaĝo tie ĉi" inputMessageHere: "Entajpu masaĝo tie ĉi"
close: "Fermi"
group: "Grupo"
groups: "Grupoj"
createGroup: "Krei grupon"
groupName: "Grupa nomo" groupName: "Grupa nomo"
members: "Membroj"
messagingWithUser: "Mesaĝado kun uzanto" messagingWithUser: "Mesaĝado kun uzanto"
messagingWithGroup: "Mesaĝi kun grupo" messagingWithGroup: "Mesaĝado kun grupo"
title: "Titolo"
text: "Teksto"
enable: "Ebligi"
next: "Sekve"
noteOf: "Noto de {user}" noteOf: "Noto de {user}"
noMessagesYet: "Neniu mesaĝo" noMessagesYet: "Neniu mesaĝo"
newMessageExists: "Vi ricevis novan mesaĝon." newMessageExists: "Vi ricevis novan mesaĝon."
onlyOneFileCanBeAttached: "Vi povas aldoni nur unu dosieron po unu mesaĝo." onlyOneFileCanBeAttached: "Vi povas aldoni nur unu dosieron po unu mesaĝo."
invitationCode: "Kodo de invito" invitationCode: "Kodo de invito"
uiLanguage: "Lingvo de la interfaco" or: "Aŭ"
language: "Lingvo"
uiLanguage: "Lingvo de la fasado"
aboutX: "Pri {x}"
useOsNativeEmojis: "Oni uzas la emoĵioj de la denaska sistemo"
youHaveNoGroups: "Neniuj grupoj"
category: "Kategorio"
tags: "Etikedoj" tags: "Etikedoj"
createAccount: "Krei konton" createAccount: "Krei konton"
existingAccount: "Ekzista konto" existingAccount: "Ekzista konto"
noFollowRequests: "Vi ne havas eksekvopetojn." fontSize: "Tipara grando"
noFollowRequests: "Vi ne havas peto de sekvado"
openImageInNewTab: "Fermi la bildon en nova tablo" openImageInNewTab: "Fermi la bildon en nova tablo"
dashboard: "Stirpanelo"
local: "Loka" local: "Loka"
remote: "Transa" remote: "Transa"
total: "Entute"
clientSettings: "Agordoj de kliento"
accountSettings: "Agordoj de Konto" accountSettings: "Agordoj de Konto"
numberOfDays: "Nombro de tagoj" numberOfDays: "Nombro de tagoj"
hideThisNote: "Kaŝi tiun noton" hideThisNote: "Kaŝi tiun noton"
objectStorageBaseUrl: "Baza URL" objectStorageBaseUrl: "Baza URL"
objectStorageRegion: "Regiono"
objectStorageUseSSL: "Oni uzas SSL"
serverLogs: "Servila protokolo"
deleteAll: "Forviŝi ĉiujn" deleteAll: "Forviŝi ĉiujn"
sounds: "Sonoj"
listen: "Aŭdi"
none: "Neniu"
showInPage: "Vidi en paĝo" showInPage: "Vidi en paĝo"
deleteAllFiles: "Forviŝi ĉiujn dosierojn" deleteAllFiles: "Forviŝi ĉiujn dosierojn"
deleteAllFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn viajn dosierojn?" deleteAllFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn viajn dosierojn?"
userSilenced: "Tiu uzanto estas mutigata." userSilenced: "Tiu uzanto estas mutigata."
menu: "Menuo"
deletedNote: "Forviŝita noto" deletedNote: "Forviŝita noto"
invisibleNote: "Malpublika noto" invisibleNote: "Malpublika noto"
poll: "Balotujo" poll: "Balotujo"
useCw: "Kaŝi enhavo"
themeEditor: "Redaktilo de koloraroj"
author: "Aŭtoro"
plugins: "Kromaĵoj"
deck: "Kartaro"
medium: "Meza"
small: "Malgranda"
edit: "Redakti" edit: "Redakti"
emailServer: "Retpoŝta servilo" emailServer: "Retpoŝta servilo"
email: "Retpoŝto" email: "Retpoŝto"
emailAddress: "Retpoŝta adreso" emailAddress: "Retpoŝta adreso"
smtpConfig: "Agordoj de la servilo SMTP"
smtpUser: "Uzantnomo" smtpUser: "Uzantnomo"
smtpPass: "Pasvorto" smtpPass: "Pasvorto"
wordMute: "Silentigo de vortoj" wordMute: "Silentigo de vortoj"
userSaysSomething: "{name} parolis ion" userSaysSomething: "{name} parolis ion"
display: "Vidi" display: "Vidi"
copy: "Kopii"
database: "Datumbazo" database: "Datumbazo"
channel: "Kanalo" channel: "Kanalo"
create: "Krei"
notificationSetting: "Agordoj de sciigoj"
useGlobalSetting: "Oni uzas malloka agordo"
fileIdOrUrl: "Dosiera identigilo aŭ URL" fileIdOrUrl: "Dosiera identigilo aŭ URL"
abuseReports: "Signali" abuseReports: "Signali"
reportAbuse: "Signali" reportAbuse: "Signali"
@ -285,45 +369,89 @@ reportAbuseOf: "Signali {name}'(o)n"
send: "Sendi" send: "Sendi"
openInNewTab: "Malfermi en nova langeto" openInNewTab: "Malfermi en nova langeto"
editTheseSettingsMayBreakAccount: "Redakti tiujn agordojn estas eble damaĝi konton." editTheseSettingsMayBreakAccount: "Redakti tiujn agordojn estas eble damaĝi konton."
public: "Publika"
i18nInfo: "Misskey estas tradukata en diversaj lingvoj far volontuloj. Oni povas kontribui por la tradukado ĉe {link}." i18nInfo: "Misskey estas tradukata en diversaj lingvoj far volontuloj. Oni povas kontribui por la tradukado ĉe {link}."
accountInfo: "Kontaj Informoj"
notesCount: "Numero de notoj"
repliesCount: "Numero de respondoj senditaj"
renotesCount: "Numero de renotoj kiun vi sendis"
repliedCount: "Numero de respondoj ricevitaj"
renotedCount: "Numero de renotoj kiun vi ricevis"
followingCount: "Numero de sekvatoj" followingCount: "Numero de sekvatoj"
followersCount: "Numero de sekvantoj" followersCount: "Numero de sekvantoj"
sentReactionsCount: "Numero de sentitaj reagoj"
receivedReactionsCount: "Numero de ricevitaj reagoj"
yes: "Jes" yes: "Jes"
no: "Ne" no: "Ne"
driveFilesCount: "Numero de dosieroj en la diskingo" driveFilesCount: "Numero de dosieroj sur la disko"
notSet: "Ne elektita"
noteFavoritesCount: "Numero de la preferataj notoj" noteFavoritesCount: "Numero de la preferataj notoj"
makeExplorable: "Igi videbla konto sur la paĝo \"Esplorado\"" contact: "Kontakto"
showTitlebar: "Montri titolobredon" makeExplorable: "Videbligi konton sur la paĝo \"Esplori\""
duplicate: "Duobligi"
left: "Maldekstra"
center: "Centra"
showTitlebar: "Montri titola stango"
clearCache: "Malplenigi staplon" clearCache: "Malplenigi staplon"
onlineUsersCount: "{n} uzanto(j) estas surlinea" onlineUsersCount: "{n} uzanto(j) estas surlinea"
nUsers: "{n} uzanto(j)" nUsers: "{n} uzanto(j)"
nNotes: "{n} notoj"
myTheme: "Miaj koloraroj"
backgroundColor: "Fona koloro"
textColor: "Teksto"
saveAs: "Konservi kiel…" saveAs: "Konservi kiel…"
value: "Valoro"
createdAt: "Kreita je" createdAt: "Kreita je"
updatedAt: "Laste ĝisdatigita" updatedAt: "Laste ĝisdatigita"
deleteConfirm: "Ĉu certas forviŝi?" deleteConfirm: "Ĉu certas forviŝi?"
closeAccount: "Forigi konton" closeAccount: "Forigi konton"
currentVersion: "Nuna versio"
latestVersion: "Plej nova versio"
youAreRunningUpToDateClient: "Vi uzas la plej novan version de via kliento."
newVersionOfClientAvailable: "Nova versio de via kliento estas disponebla."
inUse: "Uzata"
editCode: "Redakti kodon" editCode: "Redakti kodon"
emailNotification: "Sciigoj per retpoŝto" emailNotification: "Sciigoj per retpoŝto"
publish: "Publikigi" publish: "Publikigi"
inChannelSearch: "Serĉi en kanalo" inChannelSearch: "Serĉi en kanalo"
useReactionPickerForContextMenu: "Malfermu reago-elektilon per dekstro-kliki" useReactionPickerForContextMenu: "Oni malfermas reago-elektilon per dekstro-kliki"
typingUsers: "{users} estas entajpanta(j)..." typingUsers: "{users} estas entajpanta(j)..."
info: "Informoj"
unknown: "Nekonata"
online: "Surkonektita" online: "Surkonektita"
offline: "Forkonektita" offline: "Forkonektita"
instanceBlocking: "Blokado de ekzemplo" instanceBlocking: "Blokado de ekzemplo"
selectAccount: "Elekti konton" selectAccount: "Elekti konton"
user: "Uzanto" user: "Uzanto"
accounts: "Kontoj" accounts: "Kontoj"
global: "Konfederacia" high: "Alta"
middle: "Meza"
low: "Malalta"
customCss: "Uzantula CSS"
global: "Malloka"
sent: "Sendi" sent: "Sendi"
received: "Ricevita"
searchResult: "Serĉorezultoj"
hashtags: "Kradvorto" hashtags: "Kradvorto"
learnMore: "Lernu pli"
translate: "Traduki"
translatedFrom: "Tradukita el {x}"
_docs:
continueReading: "Legi plu"
features: "Funkcioj"
_gallery: _gallery:
liked: "Ŝatitaj notoj" liked: "Ŝatitaj notoj"
like: "Ŝati"
_email: _email:
_follow: _follow:
title: "Vin eksekvis" title: "Vi estas eksekvita"
_receiveFollowRequest: _receiveFollowRequest:
title: "Vi ricevis eksekvopeton." title: "Vi ricevis peton de sekvado"
_registry:
key: "Ŝlosilo"
keys: "Ŝlosiloj"
domain: "Nomregno"
createKey: "Krei ŝlosilon"
_aboutMisskey: _aboutMisskey:
about: "Misskey estas malfermitkoda programo evoluigata de syuilo ekde la 2014." about: "Misskey estas malfermitkoda programo evoluigata de syuilo ekde la 2014."
contributors: "Precipaj kontribuantoj" contributors: "Precipaj kontribuantoj"
@ -335,6 +463,10 @@ _mfm:
mention: "Mencioj" mention: "Mencioj"
hashtag: "Kradvorto" hashtag: "Kradvorto"
url: "URL" url: "URL"
link: "Ligilo"
bold: "Grasa"
small: "Malgrande"
center: "Centrigi"
inlineCode: "Kodo (en linio)" inlineCode: "Kodo (en linio)"
blockCode: "Kodo (bloko)" blockCode: "Kodo (bloko)"
inlineMath: "Formulo (en linio)" inlineMath: "Formulo (en linio)"
@ -342,6 +474,12 @@ _mfm:
quote: "Citi" quote: "Citi"
emoji: "Personecigitaj emoĵioj" emoji: "Personecigitaj emoĵioj"
search: "Serĉi" search: "Serĉi"
flip: "Inversa"
x2: "Granda"
x3: "Grandega"
x4: "Pli grandega"
_reversi:
total: "Entute"
_instanceTicker: _instanceTicker:
none: "Ne montri" none: "Ne montri"
remote: "Montri al transaj uzantoj" remote: "Montri al transaj uzantoj"
@ -349,30 +487,39 @@ _instanceTicker:
_channel: _channel:
create: "Krei kanalon" create: "Krei kanalon"
edit: "Redakti kanalon" edit: "Redakti kanalon"
following: "Sekvata" following: "Sekvante"
usersCount: "{n} partoprenanto(j)"
_menuDisplay: _menuDisplay:
hide: "Kaŝi" hide: "Kaŝi"
_wordMute: _wordMute:
muteWords: "Silentigataj vortoj" muteWords: "Kaŝigitaj vortoj"
mutedNotes: "Silentigataj notoj" mutedNotes: "Silentigataj notoj"
_theme: _theme:
code: "Kodo de koloraro" code: "Kodo de koloraro"
darken: "Malbrileco"
lighten: "Brileco"
keys: keys:
bg: "Fono"
navBg: "Fono de flanka stango"
hashtag: "Kradvorto" hashtag: "Kradvorto"
mention: "Mencioj" mention: "Mencioj"
renote: "Fari renoton" renote: "Fari renoton"
buttonBg: "Fono de butono"
driveFolderBg: "Fono de dosierujo de la disko"
_sfx: _sfx:
note: "Nova noto" note: "Nova noto"
noteMy: "Mia noto" noteMy: "Mia noto"
notification: "Sciigoj" notification: "Sciigoj"
chat: "Retbabilejo" chat: "Retbabili"
chatBg: "Retbabilejo (BG)" chatBg: "Retbabili (BG)"
antenna: "Ricevo de anteno" antenna: "Ricevo de anteno"
channel: "Sciigoj de kanalo" channel: "Sciigoj de kanalo"
_ago: _ago:
future: "Futuro"
justNow: "Ĵus"
secondsAgo: "Antaŭ {n} sekundoj" secondsAgo: "Antaŭ {n} sekundoj"
minutesAgo: "Antaŭ {n} minutoj" minutesAgo: "Antaŭ {n} minutoj"
hoursAgo: "Antaŭ {n} horoj" hoursAgo: "Antaŭ {n} horo(j)"
daysAgo: "Antaŭ {n} tagoj" daysAgo: "Antaŭ {n} tagoj"
weeksAgo: "Antaŭ {n} semajnoj" weeksAgo: "Antaŭ {n} semajnoj"
monthsAgo: "Antaŭ {n} monatoj" monthsAgo: "Antaŭ {n} monatoj"
@ -385,17 +532,17 @@ _time:
_tutorial: _tutorial:
title: "Uzado de Misskey" title: "Uzado de Misskey"
step1_1: "Bonvenon." step1_1: "Bonvenon."
step7_2: "Se vi volus scii pli pri Miskejon, volu rigardi la fakon {help}." step7_2: "Se vi volas scii pli pri Misskey, rigardu la fakon {help}."
step7_3: "Do, bonvolu amuziĝi Miskejon🚀" step7_3: "Do, bonvolu amuziĝi Misskey'on🚀"
_permissions: _permissions:
"read:blocks": "Vidi la liston de uzantoj kiun vi blokas" "read:blocks": "Vidi la liston de uzantoj kiun vi blokas"
"write:blocks": "Redakti vian liston de blokataj uzantoj" "write:blocks": "Redakti vian liston de blokataj uzantoj"
"read:drive": "Operacio por legi la informon de dosiero en via diskingo de Miskejo" "read:drive": "Operacio por legi la informon de dosiero en via disko de Misskey"
"write:drive": "Ĉia operacio por skribi, forviŝi, aŭ alimaniere ŝanĝi la informon de dosiero en via diskingo de Miskejo" "write:drive": "Ĉia operacio por skribi, forviŝi, aŭ alimaniere ŝanĝi la informon de dosiero en via disko de Misskey"
"read:favorites": "Vidi vian liston de preferatoj" "read:favorites": "Vidi vian liston de preferatoj"
"read:following": "Vidi tion kion vi sekvas" "read:following": "Vidi tiun kiun vi sekvas"
"write:following": "Sekvi kaj/aŭ malsekvi alian uzanton" "write:following": "Sekvi aŭ malsekvi alian uzanton"
"read:messaging": "Vidi via retbabilado" "read:messaging": "Vidi vian retbabiladon"
"read:mutes": "Vidi vian liston de silentigoj" "read:mutes": "Vidi vian liston de silentigoj"
"write:mutes": "Redakti vian liston de silentigoj" "write:mutes": "Redakti vian liston de silentigoj"
"write:notes": "Krei / Forviŝi noton" "write:notes": "Krei / Forviŝi noton"
@ -406,7 +553,8 @@ _permissions:
"read:page-likes": "Vidi ŝatojn de paĝo" "read:page-likes": "Vidi ŝatojn de paĝo"
"read:channels": "Vidi kanalojn" "read:channels": "Vidi kanalojn"
_antennaSources: _antennaSources:
homeTimeline: "Notoj far uzantoj sekvataj de vi" all: "Ĉiuj notoj"
homeTimeline: "Notoj far uzantoj, kiujn vi sekvas"
_weekday: _weekday:
sunday: "dimanĉo" sunday: "dimanĉo"
monday: "lundo" monday: "lundo"
@ -419,15 +567,17 @@ _widgets:
notifications: "Sciigoj" notifications: "Sciigoj"
timeline: "Templinio" timeline: "Templinio"
clock: "Horloĝo" clock: "Horloĝo"
federation: "Konfederacio" activity: "Aktiveco"
federation: "Kunfederaĵo"
slideshow: "Bildoprezento" slideshow: "Bildoprezento"
button: "Butono"
onlineUsers: "Surkonektita uzanto" onlineUsers: "Surkonektita uzanto"
_cw: _cw:
show: "Vidu pli" show: "Vidu pli"
files: "{count} dosiero(j)" files: "{count} dosiero(j)"
_poll: _poll:
choiceN: "Balotilo {n}" choiceN: "Balotilo {n}"
noMore: "Oni ne plu povas aldoni." noMore: "Oni ne povas aldoni pli."
infinite: "Neniam" infinite: "Neniam"
deadlineTime: "hor" deadlineTime: "hor"
votesCount: "{n} balotiloj" votesCount: "{n} balotiloj"
@ -438,11 +588,11 @@ _visibility:
home: "Hejmo" home: "Hejmo"
homeDescription: "Elsendi nur sur la hejmtemplinio" homeDescription: "Elsendi nur sur la hejmtemplinio"
followers: "Sekvantoj" followers: "Sekvantoj"
followersDescription: "Elsendi nur al sekvantoj al mi" followersDescription: "Nur al sekvantoj al mi"
localOnly: "Nur loka" localOnly: "Nur loka"
localOnlyDescription: "Ne montri al transaj uzantoj" localOnlyDescription: "Ne montri al transaj uzantoj"
_postForm: _postForm:
replyPlaceholder: "Respondado al tiu noto..." replyPlaceholder: "Respondi al tiu noto..."
quotePlaceholder: "Citado tiun noton..." quotePlaceholder: "Citado tiun noton..."
channelPlaceholder: "Sendi sur la kanalo" channelPlaceholder: "Sendi sur la kanalo"
_profile: _profile:
@ -450,16 +600,21 @@ _profile:
username: "Uzantnomo" username: "Uzantnomo"
metadataEdit: "Redakti kromaj informoj" metadataEdit: "Redakti kromaj informoj"
changeAvatar: "Ŝanĝi profilbildon" changeAvatar: "Ŝanĝi profilbildon"
changeBanner: "Ŝanĝi standardon"
_exportOrImport: _exportOrImport:
allNotes: "Ĉiuj notoj"
followingList: "Sekvataj" followingList: "Sekvataj"
muteList: "Silentigoj" muteList: "Silentigoj"
blockingList: "Blokado" blockingList: "Blokado"
userLists: "Listoj" userLists: "Listoj"
_charts:
federationInstancesTotal: "Tuta numero de kunfederantaj ekzemploj"
filesTotal: "Tuta numero de dosieroj"
_timelines: _timelines:
home: "Hejmo" home: "Hejmo"
local: "Loka" local: "Loka"
social: "Sociala" social: "Sociala"
global: "Konfederacia" global: "Malloka"
_rooms: _rooms:
translate: "Movi" translate: "Movi"
chooseImage: "Elekti bildon" chooseImage: "Elekti bildon"
@ -472,18 +627,26 @@ _pages:
editThisPage: "Redakti la paĝon" editThisPage: "Redakti la paĝon"
viewPage: "Vidi via paĝojn" viewPage: "Vidi via paĝojn"
my: "Miaj paĝoj" my: "Miaj paĝoj"
featured: "Ravaĵoj"
content: "Blokado de paĝo" content: "Blokado de paĝo"
url: "URL de paĝo" url: "URL de paĝo"
alignCenter: "Centrigi"
chooseBlock: "Aldoni blokon" chooseBlock: "Aldoni blokon"
blocks: blocks:
image: "Bildoj" image: "Bildo"
button: "Butono"
_post: _post:
canvasId: "Kanvasa identigilo" canvasId: "Kanvasa identigilo"
_numberInput:
text: "Titolo"
_canvas: _canvas:
id: "Kanvasa identigilo" id: "Kanvasa identigilo"
_note: _note:
id: "Identigilo de noto" id: "Identigilo de noto"
_counter:
text: "Titolo"
_button: _button:
text: "Titolo"
_action: _action:
_pushEvent: _pushEvent:
event: "Nomo de la evento" event: "Nomo de la evento"
@ -511,21 +674,23 @@ _notification:
fileUploaded: "La dosiero sukcese alŝutiĝis." fileUploaded: "La dosiero sukcese alŝutiĝis."
youGotPoll: "{name} balotis" youGotPoll: "{name} balotis"
youGotMessagingMessageFromUser: "{name} sentis mesaĝon al vi." youGotMessagingMessageFromUser: "{name} sentis mesaĝon al vi."
youWereFollowed: "Vin eksekvis" youGotMessagingMessageFromGroup: "Retbabilan mesaĝon oni sendis al la grupo {name}"
youReceivedFollowRequest: "Vi ricevis eksekvopeton." youWereFollowed: "sksekvis vin"
yourFollowRequestAccepted: "Via eksekvopeto estas akceptita." youReceivedFollowRequest: "Vi ricevis peton de sekvado"
yourFollowRequestAccepted: "Via peto por eksekvu estas akceptita."
_types: _types:
follow: "Sekvatoj" follow: "Sekvatoj"
mention: "Mencioj" mention: "Mencioj"
renote: "Fari renoton" renote: "Fari renoton"
quote: "Citi" quote: "Citi"
reaction: "Reagoj" reaction: "Reagoj"
receiveFollowRequest: "Eksekvopeto ricevita" receiveFollowRequest: "Ricevita peton de sekvado"
followRequestAccepted: "Eksekvopeto akceptiĝis." followRequestAccepted: "Peto por eksekvu akceptita"
_deck: _deck:
profile: "Agordaro" profile: "Agordaro"
_columns: _columns:
notifications: "Sciigoj" notifications: "Sciigoj"
tl: "Templinio" tl: "Templinio"
antenna: "Antenoj"
list: "Listoj" list: "Listoj"
mentions: "Al vi" mentions: "Al vi"

View file

@ -91,11 +91,11 @@ followRequests: "Demandes dabonnement"
unfollow: "Se désabonner" unfollow: "Se désabonner"
followRequestPending: "Demande d'abonnement en attente de confirmation" followRequestPending: "Demande d'abonnement en attente de confirmation"
enterEmoji: "Insérer un émoji" enterEmoji: "Insérer un émoji"
renote: "Partager" renote: "Renoter"
unrenote: "Annuler le partage" unrenote: "Annuler la Renote"
renoted: "Republié !" renoted: "Renoté !"
cantRenote: "Ce message ne peut pas être republié." cantRenote: "Ce message ne peut pas être renoté."
cantReRenote: "Impossible de repartager un partage." cantReRenote: "Impossible de renoter une Renote."
quote: "Citer" quote: "Citer"
pinnedNote: "Note épinglée" pinnedNote: "Note épinglée"
pinned: "Épingler sur le profil" pinned: "Épingler sur le profil"
@ -638,9 +638,9 @@ manageAccessTokens: "Gérer les jetons d'accès"
accountInfo: " Informations du compte " accountInfo: " Informations du compte "
notesCount: "Nombre de notes" notesCount: "Nombre de notes"
repliesCount: "Nombre de réponses envoyées" repliesCount: "Nombre de réponses envoyées"
renotesCount: "Nombre de notes repartagées" renotesCount: "Nombre de notes que vous avez renotées"
repliedCount: "Nombre de réponses reçues" repliedCount: "Nombre de réponses reçues"
renotedCount: "Nombre de Renotes" renotedCount: "Nombre de vos notes renotées"
followingCount: "Nombre de comptes suivis" followingCount: "Nombre de comptes suivis"
followersCount: "Nombre d'abonnés" followersCount: "Nombre d'abonnés"
sentReactionsCount: "Nombre de réactions envoyées" sentReactionsCount: "Nombre de réactions envoyées"
@ -767,14 +767,22 @@ customCssWarn: "Utilisez cette fonctionnalité uniquement si vous savez exacteme
global: "Global" global: "Global"
squareAvatars: "Avatars carrés" squareAvatars: "Avatars carrés"
sent: "Envoyer" sent: "Envoyer"
searchResult: "Résultats de la recherche"
hashtags: "Hashtags" hashtags: "Hashtags"
troubleshooting: "Résolution de problèmes" troubleshooting: "Résolution de problèmes"
useBlurEffect: "Utiliser des effets de flou dans l'interface"
learnMore: "Plus d'informations"
misskeyUpdated: "Misskey a été mis à jour !"
whatIsNew: "Voir les derniers changements"
translate: "Traduire"
translatedFrom: "Traduit depuis {x}"
_docs: _docs:
continueReading: "Lire plus" continueReading: "Lire plus"
features: "Fonctionnalités" features: "Fonctionnalités"
generalTopics: "Sujets généraux" generalTopics: "Sujets généraux"
advancedTopics: "Sujets avancés" advancedTopics: "Sujets avancés"
admin: "Gestion" admin: "Gestion"
translateWarn: "Ceci est une traduction dont le contenu peut différer du texte original."
_ad: _ad:
back: "Retour" back: "Retour"
reduceFrequencyOfThisAd: "Voir cette publicité moins souvent" reduceFrequencyOfThisAd: "Voir cette publicité moins souvent"
@ -988,7 +996,7 @@ _theme:
hashtag: "Hashtags" hashtag: "Hashtags"
mention: "Mentionner" mention: "Mentionner"
mentionMe: "Mentions (Moi)" mentionMe: "Mentions (Moi)"
renote: "Partager" renote: "Renoter"
modalBg: "Modal d'arrière-plan" modalBg: "Modal d'arrière-plan"
divider: "Séparateur" divider: "Séparateur"
scrollbarHandle: "Poignée de la barre de navigation" scrollbarHandle: "Poignée de la barre de navigation"

View file

@ -767,9 +767,21 @@ customCssWarn: "Pengaturan ini seharusnya digunakan jika kamu tahu cara kerjanya
global: "Global" global: "Global"
squareAvatars: "Tampilkan avatar sebagai persegi" squareAvatars: "Tampilkan avatar sebagai persegi"
sent: "Kirim" sent: "Kirim"
received: "Diterima"
searchResult: "Hasil Penelusuran"
hashtags: "Tagar" hashtags: "Tagar"
troubleshooting: "Penyelesaian Masalah"
useBlurEffect: "Gunakan efek blur pada antarmuka"
learnMore: "Pelajari lebih lanjut"
misskeyUpdated: "Misskey telah dimutakhirkan!"
whatIsNew: "Lihat perubahan pemutakhiran"
_docs: _docs:
continueReading: "Baca lebih lanjut"
features: "Fitur"
generalTopics: "Topik umum"
advancedTopics: "Topik tingkat lanjut"
admin: "Manajemen" admin: "Manajemen"
translateWarn: "Ini merupakan dokumen terjemahan. Konten di dalamnya kemungkinan dapat berbeda dari yang aslinya."
_ad: _ad:
back: "Kembali" back: "Kembali"
reduceFrequencyOfThisAd: "Tampilkan iklan ini lebih sedikit" reduceFrequencyOfThisAd: "Tampilkan iklan ini lebih sedikit"
@ -868,6 +880,8 @@ _mfm:
blurDescription: "Konten dapat diburamkan dengan efek ini. Konten dapat ditampilkan dengan jelas dengan melayangkan kursor tetikus di atasnya." blurDescription: "Konten dapat diburamkan dengan efek ini. Konten dapat ditampilkan dengan jelas dengan melayangkan kursor tetikus di atasnya."
font: "Font" font: "Font"
fontDescription: "Setel font yang ditampilkan untuk konten." fontDescription: "Setel font yang ditampilkan untuk konten."
rainbow: "Pelangi"
rainbowDescription: "Membuat konten muncul dalam warna pelangi."
_reversi: _reversi:
reversi: "Reversi" reversi: "Reversi"
gameSettings: "Pengaturan permainan" gameSettings: "Pengaturan permainan"

View file

@ -772,6 +772,11 @@ searchResult: "検索結果"
hashtags: "ハッシュタグ" hashtags: "ハッシュタグ"
troubleshooting: "トラブルシューティング" troubleshooting: "トラブルシューティング"
useBlurEffect: "UIにぼかし効果を使用" useBlurEffect: "UIにぼかし効果を使用"
learnMore: "詳しく"
misskeyUpdated: "Misskeyが更新されました"
whatIsNew: "更新情報を見る"
translate: "翻訳"
translatedFrom: "{x}から翻訳"
_docs: _docs:
continueReading: "続きを読む" continueReading: "続きを読む"

View file

@ -7,6 +7,7 @@ search: "探す"
notifications: "通知" notifications: "通知"
username: "ユーザー名" username: "ユーザー名"
password: "パスワード" password: "パスワード"
forgotPassword: "パスワード忘れてん"
fetchingAsApObject: "今ちと連合に照会しとるで" fetchingAsApObject: "今ちと連合に照会しとるで"
ok: "OKや" ok: "OKや"
gotIt: "ほい" gotIt: "ほい"
@ -139,6 +140,7 @@ flagAsBotDescription: "もしこのアカウントがプログラムによって
flagAsCat: "Catやで" flagAsCat: "Catやで"
flagAsCatDescription: "ワレ、猫ちゃんならこのフラグをつけてみ?" flagAsCatDescription: "ワレ、猫ちゃんならこのフラグをつけてみ?"
autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストを勝手に許可しとく" autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストを勝手に許可しとく"
addAccount: "アカウントを追加"
loginFailed: "ログインに失敗してしもうた…" loginFailed: "ログインに失敗してしもうた…"
showOnRemote: "リモートで見る" showOnRemote: "リモートで見る"
general: "全般" general: "全般"
@ -278,6 +280,7 @@ emptyDrive: "ドライブにはなんも残っとらん"
emptyFolder: "ふぉろだーにはなんも残っとらん" emptyFolder: "ふぉろだーにはなんも残っとらん"
unableToDelete: "消そうおもってんけどな、あかんかったわ" unableToDelete: "消そうおもってんけどな、あかんかったわ"
inputNewFileName: "今度のファイル名は何にするん?" inputNewFileName: "今度のファイル名は何にするん?"
inputNewDescription: "新しいキャプションを入力しましょ"
inputNewFolderName: "今度のフォルダ名は何にするん?" inputNewFolderName: "今度のフォルダ名は何にするん?"
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーや。" circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーや。"
hasChildFilesOrFolders: "このフォルダ、まだなんか入っとるから消されへん" hasChildFilesOrFolders: "このフォルダ、まだなんか入っとるから消されへん"

View file

@ -770,13 +770,20 @@ sent: "전송"
received: "수신" received: "수신"
searchResult: "검색 결과" searchResult: "검색 결과"
hashtags: "해시태그" hashtags: "해시태그"
troubleshooting: "트러블 슈팅" troubleshooting: "문제 해결"
useBlurEffect: "UI에 흐림 효과 사용"
learnMore: "자세히"
misskeyUpdated: "Misskey가 업데이트 되었습니다!"
whatIsNew: "패치 정보 보기"
translate: "번역"
translatedFrom: "{x}에서 번역"
_docs: _docs:
continueReading: "계속 읽기" continueReading: "계속 읽기"
features: "기능" features: "기능"
generalTopics: "일반 주제" generalTopics: "일반 주제"
advancedTopics: "심화 주제" advancedTopics: "심화 주제"
admin: "관리" admin: "관리"
translateWarn: "이 문서는 번역되었기 때문에 원본과는 내용이 다를 수 있습니다."
_ad: _ad:
back: "뒤로" back: "뒤로"
reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기" reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기"

View file

@ -529,6 +529,7 @@ removeAllFollowing: "Удалить всех подписчиков"
removeAllFollowingDescription: "Отменить все подписки с домена {host}? Пожалуйста, применяйте это действие, если инстанс больше не существует." removeAllFollowingDescription: "Отменить все подписки с домена {host}? Пожалуйста, применяйте это действие, если инстанс больше не существует."
userSuspended: "Эта учётная запись заморожена" userSuspended: "Эта учётная запись заморожена"
userSilenced: "Этот пользователь был заглушен" userSilenced: "Этот пользователь был заглушен"
menu: "Меню"
divider: "Линия-разделитель" divider: "Линия-разделитель"
addItem: "Добавить элемент" addItem: "Добавить элемент"
rooms: "Комната" rooms: "Комната"
@ -761,15 +762,26 @@ middle: "Средне"
low: "Низкий" low: "Низкий"
emailNotConfiguredWarning: "Не указан адрес электронной почты" emailNotConfiguredWarning: "Не указан адрес электронной почты"
ratio: "Соотношение" ratio: "Соотношение"
customCss: "Индивидуальный CSS"
customCssWarn: "Используйте эту настройку только если знаете, что делаете. Ошибки здесь чреваты тем, что сайт перестанет нормально работать у вас."
global: "Всеобщая" global: "Всеобщая"
squareAvatars: "Квадратные аватарки"
sent: "Отправить" sent: "Отправить"
received: "Получено"
searchResult: "Результаты поиска"
hashtags: "Хэштег" hashtags: "Хэштег"
troubleshooting: "Разрешение проблем"
useBlurEffect: "Размытие в интерфейсе"
learnMore: "Подробнее"
misskeyUpdated: "Misskey обновился!"
whatIsNew: "Что новенького?"
_docs: _docs:
continueReading: "Читать подробнее" continueReading: "Читать подробнее"
features: "Возможности" features: "Возможности"
generalTopics: "Основные темы" generalTopics: "Основные темы"
advancedTopics: "Дополнительные темы" advancedTopics: "Дополнительные темы"
admin: "Управление" admin: "Управление"
translateWarn: "Это перевод документа. Он может неточно отражать содержимое оригинала."
_ad: _ad:
back: "Выход" back: "Выход"
reduceFrequencyOfThisAd: "Реже показывать эту рекламу" reduceFrequencyOfThisAd: "Реже показывать эту рекламу"

View file

@ -771,6 +771,12 @@ received: "收取"
searchResult: "搜索结果" searchResult: "搜索结果"
hashtags: "话题标签" hashtags: "话题标签"
troubleshooting: "故障排除" troubleshooting: "故障排除"
useBlurEffect: "在UI上使用模糊效果"
learnMore: "更多信息"
misskeyUpdated: "Misskey更新完成"
whatIsNew: "显示更新信息"
translate: "翻译"
translatedFrom: "从 {x} 翻译"
_docs: _docs:
continueReading: "继续阅读" continueReading: "继续阅读"
features: "特性" features: "特性"

View file

@ -0,0 +1,182 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class chartReindex1629004542760 implements MigrationInterface {
name = 'chartReindex1629004542760'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DELETE FROM "__chart__active_users" a USING "__chart__active_users" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__drive" a USING "__chart__drive" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__federation" a USING "__chart__federation" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__hashtag" a USING "__chart__hashtag" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__instance" a USING "__chart__instance" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__network" a USING "__chart__network" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__notes" a USING "__chart__notes" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__per_user_drive" a USING "__chart__per_user_drive" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__per_user_following" a USING "__chart__per_user_following" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__per_user_notes" a USING "__chart__per_user_notes" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__per_user_reaction" a USING "__chart__per_user_reaction" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__test_grouped" a USING "__chart__test_grouped" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__test_unique" a USING "__chart__test_unique" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__users" a USING "__chart__users" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DROP INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc"`);
await queryRunner.query(`DROP INDEX "IDX_00ed5f86db1f7efafb1978bf21"`);
await queryRunner.query(`DROP INDEX "IDX_9a3ed15a30ab7e3a37702e6e08"`);
await queryRunner.query(`DROP INDEX "IDX_13565815f618a1ff53886c5b28"`);
await queryRunner.query(`DROP INDEX "IDX_7a170f67425e62a8fabb76c872"`);
await queryRunner.query(`DROP INDEX "IDX_3313d7288855ec105b5bbf6c21"`);
await queryRunner.query(`DROP INDEX "IDX_36cb699c49580d4e6c2e6159f9"`);
await queryRunner.query(`DROP INDEX "IDX_76e87c7bfc5d925fcbba405d84"`);
await queryRunner.query(`DROP INDEX "IDX_dd907becf76104e4b656659e6b"`);
await queryRunner.query(`DROP INDEX "IDX_07747a1038c05f532a718fe1de"`);
await queryRunner.query(`DROP INDEX "IDX_99a7d2faaef84a6f728d714ad6"`);
await queryRunner.query(`DROP INDEX "IDX_25a97c02003338124b2b75fdbc"`);
await queryRunner.query(`DROP INDEX "IDX_6b8f34a1a64b06014b6fb66824"`);
await queryRunner.query(`DROP INDEX "IDX_da8a46ba84ca1d8bb5a29bfb63"`);
await queryRunner.query(`DROP INDEX "IDX_39ee857ab2f23493037c6b6631"`);
await queryRunner.query(`DROP INDEX "IDX_a1efd3e0048a5f2793a47360dc"`);
await queryRunner.query(`DROP INDEX "IDX_7b5da130992ec9df96712d4290"`);
await queryRunner.query(`DROP INDEX "IDX_0a905b992fecd2b5c3fb98759e"`);
await queryRunner.query(`DROP INDEX "IDX_42eb716a37d381cdf566192b2b"`);
await queryRunner.query(`DROP INDEX "IDX_7036f2957151588b813185c794"`);
await queryRunner.query(`DROP INDEX "IDX_f09d543e3acb16c5976bdb31fa"`);
await queryRunner.query(`DROP INDEX "IDX_5f86db6492274e07c1a3cdf286"`);
await queryRunner.query(`DROP INDEX "IDX_e496ca8096d28f6b9b509264dc"`);
await queryRunner.query(`DROP INDEX "IDX_30bf67687f483ace115c5ca642"`);
await queryRunner.query(`DROP INDEX "IDX_7af07790712aa3438ff6773f3b"`);
await queryRunner.query(`DROP INDEX "IDX_4b3593098b6edc9c5afe36b18b"`);
await queryRunner.query(`DROP INDEX "IDX_b77d4dd9562c3a899d9a286fcd"`);
await queryRunner.query(`DROP INDEX "IDX_84234bd1abb873f07329681c83"`);
await queryRunner.query(`DROP INDEX "IDX_55bf20f366979f2436de99206b"`);
await queryRunner.query(`DROP INDEX "IDX_5048e9daccbbbc6d567bb142d3"`);
await queryRunner.query(`DROP INDEX "IDX_f7bf4c62059764c2c2bb40fdab"`);
await queryRunner.query(`DROP INDEX "IDX_8cf3156fd7a6b15c43459c6e3b"`);
await queryRunner.query(`DROP INDEX "IDX_229a41ad465f9205f1f5703291"`);
await queryRunner.query(`DROP INDEX "IDX_0c641990ecf47d2545df4edb75"`);
await queryRunner.query(`DROP INDEX "IDX_234dff3c0b56a6150b95431ab9"`);
await queryRunner.query(`DROP INDEX "IDX_b14489029e4b3aaf4bba5fb524"`);
await queryRunner.query(`DROP INDEX "IDX_437bab3c6061d90f6bb65fd2cc"`);
await queryRunner.query(`DROP INDEX "IDX_bbfa573a8181018851ed0b6357"`);
await queryRunner.query(`DROP INDEX "IDX_a0cd75442dd10d0643a17c4a49"`);
await queryRunner.query(`DROP INDEX "IDX_b070a906db04b44c67c6c2144d"`);
await queryRunner.query(`DROP INDEX "IDX_d41cce6aee1a50bfc062038f9b"`);
await queryRunner.query(`DROP INDEX "IDX_a319e5dbf47e8a17497623beae"`);
await queryRunner.query(`DROP INDEX "IDX_845254b3eaf708ae8a6cac3026"`);
await queryRunner.query(`DROP INDEX "IDX_ed9b95919c672a13008e9487ee"`);
await queryRunner.query(`DROP INDEX "IDX_337e9599f278bd7537fe30876f"`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_9a3ed15a30ab7e3a37702e6e08" ON "__chart__active_users" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_60c5c6e7e538c09aa274ecd1cf" ON "__chart__active_users" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_3313d7288855ec105b5bbf6c21" ON "__chart__drive" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ceab80a6729f8e2e6f5b8a1a3d" ON "__chart__drive" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_dd907becf76104e4b656659e6b" ON "__chart__federation" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_eddfed8fb40305a04c6f941050" ON "__chart__federation" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_25a97c02003338124b2b75fdbc" ON "__chart__hashtag" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_53a3604b939e2b479eb2cfaac8" ON "__chart__hashtag" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_39ee857ab2f23493037c6b6631" ON "__chart__instance" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_8111b817b9818c04d7eb8475b1" ON "__chart__instance" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a905b992fecd2b5c3fb98759e" ON "__chart__network" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_2082327b2699ce924fa654afc5" ON "__chart__network" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_f09d543e3acb16c5976bdb31fa" ON "__chart__notes" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e60c358aaced5aab8900a4af31" ON "__chart__notes" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_30bf67687f483ace115c5ca642" ON "__chart__per_user_drive" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a9a806d466b314f253a1a611c4" ON "__chart__per_user_drive" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b77d4dd9562c3a899d9a286fcd" ON "__chart__per_user_following" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_dabbb38a51ab86ee3cab291326" ON "__chart__per_user_following" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5048e9daccbbbc6d567bb142d3" ON "__chart__per_user_notes" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_583a157ed0cf0ed1b5ec2a833f" ON "__chart__per_user_notes" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_229a41ad465f9205f1f5703291" ON "__chart__per_user_reaction" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_3b7697a96f522d0478972e6d6f" ON "__chart__per_user_reaction" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b14489029e4b3aaf4bba5fb524" ON "__chart__test_grouped" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_da522b4008a9f5d7743b87ad55" ON "__chart__test_grouped" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a0cd75442dd10d0643a17c4a49" ON "__chart__test_unique" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_16effb2e888f6763673b579f80" ON "__chart__test_unique" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a319e5dbf47e8a17497623beae" ON "__chart__test" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_dab383a36f3c9db4a0c9b02cf3" ON "__chart__test" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_337e9599f278bd7537fe30876f" ON "__chart__users" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_66feba81e1795d176d06c0b1e6" ON "__chart__users" ("date") WHERE "group" IS NULL`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_66feba81e1795d176d06c0b1e6"`);
await queryRunner.query(`DROP INDEX "IDX_337e9599f278bd7537fe30876f"`);
await queryRunner.query(`DROP INDEX "IDX_dab383a36f3c9db4a0c9b02cf3"`);
await queryRunner.query(`DROP INDEX "IDX_a319e5dbf47e8a17497623beae"`);
await queryRunner.query(`DROP INDEX "IDX_16effb2e888f6763673b579f80"`);
await queryRunner.query(`DROP INDEX "IDX_a0cd75442dd10d0643a17c4a49"`);
await queryRunner.query(`DROP INDEX "IDX_da522b4008a9f5d7743b87ad55"`);
await queryRunner.query(`DROP INDEX "IDX_b14489029e4b3aaf4bba5fb524"`);
await queryRunner.query(`DROP INDEX "IDX_3b7697a96f522d0478972e6d6f"`);
await queryRunner.query(`DROP INDEX "IDX_229a41ad465f9205f1f5703291"`);
await queryRunner.query(`DROP INDEX "IDX_583a157ed0cf0ed1b5ec2a833f"`);
await queryRunner.query(`DROP INDEX "IDX_5048e9daccbbbc6d567bb142d3"`);
await queryRunner.query(`DROP INDEX "IDX_dabbb38a51ab86ee3cab291326"`);
await queryRunner.query(`DROP INDEX "IDX_b77d4dd9562c3a899d9a286fcd"`);
await queryRunner.query(`DROP INDEX "IDX_a9a806d466b314f253a1a611c4"`);
await queryRunner.query(`DROP INDEX "IDX_30bf67687f483ace115c5ca642"`);
await queryRunner.query(`DROP INDEX "IDX_e60c358aaced5aab8900a4af31"`);
await queryRunner.query(`DROP INDEX "IDX_f09d543e3acb16c5976bdb31fa"`);
await queryRunner.query(`DROP INDEX "IDX_2082327b2699ce924fa654afc5"`);
await queryRunner.query(`DROP INDEX "IDX_0a905b992fecd2b5c3fb98759e"`);
await queryRunner.query(`DROP INDEX "IDX_8111b817b9818c04d7eb8475b1"`);
await queryRunner.query(`DROP INDEX "IDX_39ee857ab2f23493037c6b6631"`);
await queryRunner.query(`DROP INDEX "IDX_53a3604b939e2b479eb2cfaac8"`);
await queryRunner.query(`DROP INDEX "IDX_25a97c02003338124b2b75fdbc"`);
await queryRunner.query(`DROP INDEX "IDX_eddfed8fb40305a04c6f941050"`);
await queryRunner.query(`DROP INDEX "IDX_dd907becf76104e4b656659e6b"`);
await queryRunner.query(`DROP INDEX "IDX_ceab80a6729f8e2e6f5b8a1a3d"`);
await queryRunner.query(`DROP INDEX "IDX_3313d7288855ec105b5bbf6c21"`);
await queryRunner.query(`DROP INDEX "IDX_60c5c6e7e538c09aa274ecd1cf"`);
await queryRunner.query(`DROP INDEX "IDX_9a3ed15a30ab7e3a37702e6e08"`);
await queryRunner.query(`DROP INDEX "IDX_a9021cc2e1feb5f72d3db6e9f5"`);
await queryRunner.query(`DROP INDEX "IDX_f22169eb10657bded6d875ac8f"`);
await queryRunner.query(`DROP INDEX "IDX_c8cc87bd0f2f4487d17c651fbf"`);
await queryRunner.query(`DROP INDEX "IDX_754499f9b2642336433769518d"`);
await queryRunner.query(`DROP INDEX "IDX_315c779174fe8247ab324f036e"`);
await queryRunner.query(`DROP INDEX "IDX_c5d46cbfda48b1c33ed852e21b"`);
await queryRunner.query(`CREATE INDEX "IDX_337e9599f278bd7537fe30876f" ON "__chart__users" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_ed9b95919c672a13008e9487ee" ON "__chart__users" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_845254b3eaf708ae8a6cac3026" ON "__chart__users" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_a319e5dbf47e8a17497623beae" ON "__chart__test" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_d41cce6aee1a50bfc062038f9b" ON "__chart__test" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_b070a906db04b44c67c6c2144d" ON "__chart__test" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_a0cd75442dd10d0643a17c4a49" ON "__chart__test_unique" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_bbfa573a8181018851ed0b6357" ON "__chart__test_unique" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_437bab3c6061d90f6bb65fd2cc" ON "__chart__test_unique" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_b14489029e4b3aaf4bba5fb524" ON "__chart__test_grouped" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_234dff3c0b56a6150b95431ab9" ON "__chart__test_grouped" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_0c641990ecf47d2545df4edb75" ON "__chart__test_grouped" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_229a41ad465f9205f1f5703291" ON "__chart__per_user_reaction" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_8cf3156fd7a6b15c43459c6e3b" ON "__chart__per_user_reaction" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_f7bf4c62059764c2c2bb40fdab" ON "__chart__per_user_reaction" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_5048e9daccbbbc6d567bb142d3" ON "__chart__per_user_notes" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_55bf20f366979f2436de99206b" ON "__chart__per_user_notes" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_84234bd1abb873f07329681c83" ON "__chart__per_user_notes" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_b77d4dd9562c3a899d9a286fcd" ON "__chart__per_user_following" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_4b3593098b6edc9c5afe36b18b" ON "__chart__per_user_following" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_7af07790712aa3438ff6773f3b" ON "__chart__per_user_following" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_30bf67687f483ace115c5ca642" ON "__chart__per_user_drive" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_e496ca8096d28f6b9b509264dc" ON "__chart__per_user_drive" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_5f86db6492274e07c1a3cdf286" ON "__chart__per_user_drive" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_f09d543e3acb16c5976bdb31fa" ON "__chart__notes" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_7036f2957151588b813185c794" ON "__chart__notes" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_42eb716a37d381cdf566192b2b" ON "__chart__notes" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_0a905b992fecd2b5c3fb98759e" ON "__chart__network" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_7b5da130992ec9df96712d4290" ON "__chart__network" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_a1efd3e0048a5f2793a47360dc" ON "__chart__network" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_39ee857ab2f23493037c6b6631" ON "__chart__instance" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_da8a46ba84ca1d8bb5a29bfb63" ON "__chart__instance" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_6b8f34a1a64b06014b6fb66824" ON "__chart__instance" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_25a97c02003338124b2b75fdbc" ON "__chart__hashtag" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_99a7d2faaef84a6f728d714ad6" ON "__chart__hashtag" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_07747a1038c05f532a718fe1de" ON "__chart__hashtag" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_dd907becf76104e4b656659e6b" ON "__chart__federation" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_76e87c7bfc5d925fcbba405d84" ON "__chart__federation" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_36cb699c49580d4e6c2e6159f9" ON "__chart__federation" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_3313d7288855ec105b5bbf6c21" ON "__chart__drive" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_7a170f67425e62a8fabb76c872" ON "__chart__drive" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_13565815f618a1ff53886c5b28" ON "__chart__drive" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_9a3ed15a30ab7e3a37702e6e08" ON "__chart__active_users" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_00ed5f86db1f7efafb1978bf21" ON "__chart__active_users" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc" ON "__chart__active_users" ("date") `);
}
}

View file

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class deeplIntegration1629024377804 implements MigrationInterface {
name = 'deeplIntegration1629024377804'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "meta" ADD "deeplAuthKey" character varying(128)`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "deeplAuthKey"`);
}
}

View file

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class fixChannelUserId1629288472000 implements MigrationInterface {
name = 'fixChannelUserId1629288472000'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "channel" ALTER COLUMN "userId" DROP NOT NULL;`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "channel" ALTER COLUMN "userId" SET NOT NULL;`);
}
}

View file

@ -1,7 +1,7 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>", "author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.86.0", "version": "12.88.0",
"codename": "indigo", "codename": "indigo",
"repository": { "repository": {
"type": "git", "type": "git",
@ -10,7 +10,8 @@
"main": "./index.js", "main": "./index.js",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "node ./index.js", "start": "node --experimental-json-modules ./index.js",
"start:test": "cross-env NODE_ENV=test node --experimental-json-modules ./index.js",
"init": "npm run migrate", "init": "npm run migrate",
"ormconfig": "node ./built/ormconfig.js", "ormconfig": "node ./built/ormconfig.js",
"migrate": "ts-node ./node_modules/typeorm/cli.js migration:run", "migrate": "ts-node ./node_modules/typeorm/cli.js migration:run",
@ -26,6 +27,9 @@
"clean": "gulp clean", "clean": "gulp clean",
"cleanall": "gulp cleanall", "cleanall": "gulp cleanall",
"lint": "tslint 'src/**/*.ts'", "lint": "tslint 'src/**/*.ts'",
"cy:open": "cypress open",
"cy:run": "cypress run",
"e2e": "start-server-and-test start:test http://localhost cy:run",
"test": "cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha", "test": "cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
"format": "gulp format" "format": "gulp format"
}, },
@ -34,7 +38,6 @@
"lodash": "^4.17.21" "lodash": "^4.17.21"
}, },
"dependencies": { "dependencies": {
"@babel/plugin-transform-runtime": "7.14.5",
"@elastic/elasticsearch": "7.11.0", "@elastic/elasticsearch": "7.11.0",
"@koa/cors": "3.1.0", "@koa/cors": "3.1.0",
"@koa/multer": "3.0.0", "@koa/multer": "3.0.0",
@ -44,7 +47,7 @@
"@sinonjs/fake-timers": "7.1.2", "@sinonjs/fake-timers": "7.1.2",
"@syuilo/aiscript": "0.11.1", "@syuilo/aiscript": "0.11.1",
"@types/bcryptjs": "2.4.2", "@types/bcryptjs": "2.4.2",
"@types/bull": "3.15.2", "@types/bull": "3.15.3",
"@types/cbor": "6.0.0", "@types/cbor": "6.0.0",
"@types/dateformat": "3.0.1", "@types/dateformat": "3.0.1",
"@types/escape-regexp": "0.0.0", "@types/escape-regexp": "0.0.0",
@ -57,8 +60,8 @@
"@types/jsonld": "1.5.6", "@types/jsonld": "1.5.6",
"@types/katex": "0.11.1", "@types/katex": "0.11.1",
"@types/koa": "2.13.4", "@types/koa": "2.13.4",
"@types/koa-bodyparser": "4.3.2", "@types/koa-bodyparser": "4.3.3",
"@types/koa-cors": "0.0.1", "@types/koa-cors": "0.0.2",
"@types/koa-favicon": "2.0.21", "@types/koa-favicon": "2.0.21",
"@types/koa-logger": "3.1.1", "@types/koa-logger": "3.1.1",
"@types/koa-mount": "4.0.0", "@types/koa-mount": "4.0.0",
@ -68,10 +71,10 @@
"@types/koa__multer": "2.0.3", "@types/koa__multer": "2.0.3",
"@types/koa__router": "8.0.7", "@types/koa__router": "8.0.7",
"@types/markdown-it": "12.0.3", "@types/markdown-it": "12.0.3",
"@types/matter-js": "0.17.3", "@types/matter-js": "0.17.5",
"@types/mocha": "8.2.3", "@types/mocha": "8.2.3",
"@types/node": "16.3.3", "@types/node": "16.6.2",
"@types/node-fetch": "2.5.11", "@types/node-fetch": "2.5.12",
"@types/nodemailer": "6.4.4", "@types/nodemailer": "6.4.4",
"@types/nprogress": "0.2.0", "@types/nprogress": "0.2.0",
"@types/oauth": "0.9.1", "@types/oauth": "0.9.1",
@ -86,9 +89,9 @@
"@types/redis": "2.8.31", "@types/redis": "2.8.31",
"@types/rename": "1.0.4", "@types/rename": "1.0.4",
"@types/request-stats": "3.0.0", "@types/request-stats": "3.0.0",
"@types/rimraf": "3.0.1", "@types/rimraf": "3.0.2",
"@types/seedrandom": "2.4.28", "@types/seedrandom": "2.4.28",
"@types/sharp": "0.28.4", "@types/sharp": "0.28.5",
"@types/sinonjs__fake-timers": "6.0.3", "@types/sinonjs__fake-timers": "6.0.3",
"@types/speakeasy": "2.0.6", "@types/speakeasy": "2.0.6",
"@types/throttle-debounce": "2.1.0", "@types/throttle-debounce": "2.1.0",
@ -98,40 +101,40 @@
"@types/web-push": "3.3.2", "@types/web-push": "3.3.2",
"@types/webpack": "5.28.0", "@types/webpack": "5.28.0",
"@types/webpack-stream": "3.2.12", "@types/webpack-stream": "3.2.12",
"@types/websocket": "1.0.3", "@types/websocket": "1.0.4",
"@types/ws": "7.4.6", "@types/ws": "7.4.7",
"@typescript-eslint/parser": "4.28.3", "@typescript-eslint/parser": "4.29.2",
"@vue/compiler-sfc": "3.2.1", "@vue/compiler-sfc": "3.2.4",
"abort-controller": "3.0.0", "abort-controller": "3.0.0",
"apexcharts": "3.27.2", "apexcharts": "3.27.3",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autosize": "4.0.4", "autosize": "4.0.4",
"autwh": "0.1.0", "autwh": "0.1.0",
"aws-sdk": "2.948.0", "aws-sdk": "2.966.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "1.1.3", "blurhash": "1.1.4",
"broadcast-channel": "3.7.0", "broadcast-channel": "4.2.0",
"bull": "3.26.0", "bull": "3.28.1",
"cacheable-lookup": "6.0.0",
"cafy": "15.2.1", "cafy": "15.2.1",
"cbor": "7.0.6", "cbor": "8.0.0",
"chalk": "4.1.1", "chalk": "4.1.2",
"chart.js": "2.9.4", "chart.js": "2.9.4",
"cli-highlight": "2.1.11", "cli-highlight": "2.1.11",
"commander": "7.2.0", "commander": "8.1.0",
"concurrently": "6.2.0", "compare-versions": "3.6.0",
"concurrently": "6.2.1",
"content-disposition": "0.5.3", "content-disposition": "0.5.3",
"core-js": "3.15.2",
"crc-32": "1.2.0", "crc-32": "1.2.0",
"css-loader": "6.0.0", "css-loader": "6.2.0",
"cssnano": "5.0.6", "cssnano": "5.0.8",
"dateformat": "4.5.1", "dateformat": "4.5.1",
"diskusage": "1.1.3",
"escape-regexp": "0.0.1", "escape-regexp": "0.0.1",
"eslint": "7.30.0", "eslint": "7.32.0",
"eslint-plugin-vue": "7.13.0", "eslint-plugin-vue": "7.16.0",
"eventemitter3": "4.0.7", "eventemitter3": "4.0.7",
"feed": "4.2.2", "feed": "4.2.2",
"file-type": "16.5.1", "file-type": "16.5.3",
"fluent-ffmpeg": "2.1.2", "fluent-ffmpeg": "2.1.2",
"glob": "7.1.7", "glob": "7.1.7",
"got": "11.8.2", "got": "11.8.2",
@ -141,22 +144,18 @@
"gulp-replace": "1.1.3", "gulp-replace": "1.1.3",
"gulp-terser": "2.0.1", "gulp-terser": "2.0.1",
"gulp-tslint": "8.1.4", "gulp-tslint": "8.1.4",
"hard-source-webpack-plugin": "0.13.1", "hpagent": "0.1.2",
"html-minifier": "4.0.0",
"http-proxy-agent": "4.0.1",
"http-signature": "1.3.5", "http-signature": "1.3.5",
"https-proxy-agent": "5.0.0",
"idb-keyval": "5.1.3", "idb-keyval": "5.1.3",
"insert-text-at-cursor": "0.3.0", "insert-text-at-cursor": "0.3.0",
"is-root": "2.1.0",
"is-svg": "4.3.1", "is-svg": "4.3.1",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"jsdom": "16.6.0", "jsdom": "16.7.0",
"json5": "2.2.0", "json5": "2.2.0",
"json5-loader": "4.0.1", "json5-loader": "4.0.1",
"jsonld": "5.2.0", "jsonld": "5.2.0",
"jsrsasign": "8.0.20", "jsrsasign": "8.0.20",
"katex": "0.13.11", "katex": "0.13.13",
"koa": "2.13.1", "koa": "2.13.1",
"koa-bodyparser": "4.3.0", "koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0", "koa-favicon": "2.1.0",
@ -167,30 +166,26 @@
"koa-slow": "2.1.0", "koa-slow": "2.1.0",
"koa-views": "7.0.1", "koa-views": "7.0.1",
"langmap": "0.0.16", "langmap": "0.0.16",
"lookup-dns-cache": "2.1.0", "markdown-it": "12.2.0",
"markdown-it": "12.1.0",
"markdown-it-anchor": "7.1.0", "markdown-it-anchor": "7.1.0",
"matter-js": "0.17.1", "matter-js": "0.17.1",
"mfm-js": "0.19.0", "mfm-js": "0.19.0",
"misskey-js": "0.0.6", "misskey-js": "0.0.6",
"mocha": "8.4.0", "mocha": "8.4.0",
"moji": "0.5.1",
"ms": "2.1.3", "ms": "2.1.3",
"multer": "1.4.2", "multer": "1.4.3",
"nested-property": "4.0.0", "nested-property": "4.0.0",
"node-fetch": "2.6.1", "node-fetch": "2.6.1",
"nodemailer": "6.6.3", "nodemailer": "6.6.3",
"object-assign-deep": "0.4.0",
"os-utils": "0.0.14", "os-utils": "0.0.14",
"parse5": "6.0.1", "parse5": "6.0.1",
"pg": "8.6.0", "pg": "8.7.1",
"portscanner": "2.2.0", "portscanner": "2.2.0",
"postcss": "8.3.5", "postcss": "8.3.6",
"postcss-loader": "6.1.1", "postcss-loader": "6.1.1",
"prismjs": "1.24.1", "prismjs": "1.24.1",
"probe-image-size": "7.2.1", "probe-image-size": "7.2.1",
"promise-limit": "2.7.0", "promise-limit": "2.7.0",
"promise-sequential": "1.1.1",
"pug": "3.0.2", "pug": "3.0.2",
"punycode": "2.1.1", "punycode": "2.1.1",
"pureimage": "0.3.2", "pureimage": "0.3.2",
@ -198,67 +193,62 @@
"random-seed": "0.3.0", "random-seed": "0.3.0",
"ratelimiter": "3.4.1", "ratelimiter": "3.4.1",
"re2": "1.16.0", "re2": "1.16.0",
"reconnecting-websocket": "4.4.0",
"redis": "3.1.2", "redis": "3.1.2",
"redis-lock": "0.1.4", "redis-lock": "0.1.4",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"regenerator-runtime": "0.13.7",
"rename": "1.0.4", "rename": "1.0.4",
"request-stats": "3.0.0", "request-stats": "3.0.0",
"require-all": "3.0.0", "require-all": "3.0.0",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"rndstr": "1.0.0", "rndstr": "1.0.0",
"s-age": "1.1.2", "s-age": "1.1.2",
"sass": "1.35.2", "sass": "1.38.0",
"sass-loader": "12.1.0", "sass-loader": "12.1.0",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
"sharp": "0.28.3", "sharp": "0.29.0",
"speakeasy": "2.0.0", "speakeasy": "2.0.0",
"stringz": "2.1.0", "stringz": "2.1.0",
"style-loader": "3.1.0", "style-loader": "3.2.1",
"summaly": "2.4.0", "summaly": "2.4.1",
"syslog-pro": "1.0.0", "syslog-pro": "1.0.0",
"systeminformation": "5.7.7", "systeminformation": "5.8.0",
"syuilo-password-strength": "0.0.1", "syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.117.1", "three": "0.117.1",
"throttle-debounce": "3.0.1", "throttle-debounce": "3.0.1",
"tinycolor2": "1.4.2", "tinycolor2": "1.4.2",
"tmp": "0.2.1", "tmp": "0.2.1",
"ts-loader": "9.2.3", "ts-loader": "9.2.5",
"ts-node": "10.1.0", "ts-node": "10.2.1",
"tsc-alias": "1.3.7", "tsc-alias": "1.3.9",
"tsconfig-paths": "3.10.1", "tsconfig-paths": "3.10.1",
"tslint": "6.1.3", "tslint": "6.1.3",
"tslint-sonarts": "1.9.0", "tslint-sonarts": "1.9.0",
"twemoji-parser": "13.1.0", "twemoji-parser": "13.1.0",
"typeorm": "0.2.32", "typeorm": "0.2.37",
"typescript": "4.3.5", "typescript": "4.3.5",
"ulid": "2.3.0", "ulid": "2.3.0",
"uuid": "8.3.2", "uuid": "8.3.2",
"v-debounce": "0.1.2", "v-debounce": "0.1.2",
"vanilla-tilt": "1.7.0", "vue": "3.2.4",
"vue": "3.2.1", "vue-loader": "16.5.0",
"vue-color": "2.8.1",
"vue-json-pretty": "1.8.1",
"vue-loader": "16.3.1",
"vue-prism-editor": "2.0.0-alpha.2", "vue-prism-editor": "2.0.0-alpha.2",
"vue-router": "4.0.5", "vue-router": "4.0.5",
"vue-style-loader": "4.1.3", "vue-style-loader": "4.1.3",
"vue-svg-loader": "0.17.0-beta.2", "vue-svg-loader": "0.17.0-beta.2",
"vuedraggable": "4.0.1", "vuedraggable": "4.0.1",
"web-push": "3.4.5", "web-push": "3.4.5",
"webpack": "5.45.1", "webpack": "5.51.0",
"webpack-cli": "4.7.2", "webpack-cli": "4.8.0",
"websocket": "1.0.34", "websocket": "1.0.34",
"ws": "7.5.3", "ws": "8.2.0",
"xev": "2.0.1" "xev": "2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@redocly/openapi-core": "1.0.0-beta.44", "@redocly/openapi-core": "1.0.0-beta.44",
"@types/chai": "4.2.16",
"@types/fluent-ffmpeg": "2.1.17", "@types/fluent-ffmpeg": "2.1.17",
"chai": "4.3.4", "cross-env": "7.0.3",
"cross-env": "7.0.3" "cypress": "8.3.0",
"start-server-and-test": "1.13.1"
} }
} }

View file

@ -1,7 +0,0 @@
declare module 'is-root' {
function isRoot(): boolean;
namespace isRoot {} // Hack
export = isRoot;
}

View file

@ -1,9 +0,0 @@
declare module 'lookup-dns-cache' {
import { LookupOneOptions, LookupAllOptions, LookupOptions, LookupAddress } from 'dns';
function lookup(hostname: string, family: number, callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void): void;
function lookup(hostname: string, options: LookupOneOptions, callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void): void;
function lookup(hostname: string, options: LookupAllOptions, callback: (err: NodeJS.ErrnoException | null, addresses: LookupAddress[]) => void): void;
function lookup(hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, address: string | LookupAddress[], family: number) => void): void;
function lookup(hostname: string, callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void): void;
}

View file

@ -1,24 +1,23 @@
import { Command } from 'commander'; import { Command } from 'commander';
import config from '@/config'; import config from '@/config/index';
const program = new Command(); const program = new Command();
program program.version(config.version);
.version(config.version) program.option('--no-daemons', 'Disable daemon processes (for debbuging)');
.option('--no-daemons', 'Disable daemon processes (for debbuging)') program.option('--disable-clustering', 'Disable clustering');
.option('--disable-clustering', 'Disable clustering') program.option('--only-server', 'Run server only (without job queue processing)');
.option('--only-server', 'Run server only (without job queue processing)') program.option('--only-queue', 'Pocessing job queue only (without server)');
.option('--only-queue', 'Pocessing job queue only (without server)') program.option('--quiet', 'Suppress all logs');
.option('--quiet', 'Suppress all logs') program.option('--verbose', 'Enable all logs');
.option('--verbose', 'Enable all logs') program.option('--with-log-time', 'Include timestamp for each logs');
.option('--with-log-time', 'Include timestamp for each logs') program.option('--slow', 'Delay all requests (for debbuging)');
.option('--slow', 'Delay all requests (for debbuging)') program.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.');
.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.') program.parse(process.argv);
.parse(process.argv);
if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true; if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true;
if (process.env.NODE_ENV === 'test') program.disableClustering = true; if (process.env.NODE_ENV === 'test') program.disableClustering = true;
if (process.env.NODE_ENV === 'test') program.quiet = true; //if (process.env.NODE_ENV === 'test') program.quiet = true;
if (process.env.NODE_ENV === 'test') program.noDaemons = true; if (process.env.NODE_ENV === 'test') program.noDaemons = true;
export { program }; export { program };

View file

@ -2,7 +2,7 @@ import * as cluster from 'cluster';
import * as chalk from 'chalk'; import * as chalk from 'chalk';
import Xev from 'xev'; import Xev from 'xev';
import Logger from '../services/logger'; import Logger from '@/services/logger';
import { program } from '../argv'; import { program } from '../argv';
// for typeorm // for typeorm

View file

@ -2,17 +2,16 @@ import * as os from 'os';
import * as cluster from 'cluster'; import * as cluster from 'cluster';
import * as chalk from 'chalk'; import * as chalk from 'chalk';
import * as portscanner from 'portscanner'; import * as portscanner from 'portscanner';
import * as isRoot from 'is-root';
import { getConnection } from 'typeorm'; import { getConnection } from 'typeorm';
import Logger from '../services/logger'; import Logger from '@/services/logger';
import loadConfig from '@/config/load'; import loadConfig from '@/config/load';
import { Config } from '@/config/types'; import { Config } from '@/config/types';
import { lessThan } from '../prelude/array'; import { lessThan } from '@/prelude/array';
import { program } from '../argv'; import { program } from '../argv';
import { showMachineInfo } from '@/misc/show-machine-info'; import { showMachineInfo } from '@/misc/show-machine-info';
import { initDb } from '../db/postgre'; import { initDb } from '../db/postgre';
const meta = require('../meta.json'); import * as meta from '../meta.json';
const logger = new Logger('core', 'cyan'); const logger = new Logger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta', false); const bootLogger = logger.createSubLogger('boot', 'magenta', false);
@ -39,6 +38,11 @@ function greet() {
bootLogger.info(`Misskey v${meta.version}`, null, true); bootLogger.info(`Misskey v${meta.version}`, null, true);
} }
function isRoot() {
// maybe process.getuid will be undefined under not POSIX environment (e.g. Windows)
return process.getuid != null && process.getuid() === 0;
}
/** /**
* Init master process * Init master process
*/ */

View file

@ -35,6 +35,7 @@ import { twemojiSvgBase } from '@/misc/twemoji-base';
import { getStaticImageUrl } from '@client/scripts/get-static-image-url'; import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
import { acct } from '@client/filters/user'; import { acct } from '@client/filters/user';
import * as os from '@client/os'; import * as os from '@client/os';
import { instance } from '@client/instance';
type EmojiDef = { type EmojiDef = {
emoji: string; emoji: string;
@ -75,6 +76,36 @@ for (const x of lib) {
emjdb.sort((a, b) => a.name.length - b.name.length); emjdb.sort((a, b) => a.name.length - b.name.length);
//#region Construct Emoji DB
const customEmojis = instance.emojis;
const emojiDefinitions: EmojiDef[] = [];
for (const x of customEmojis) {
emojiDefinitions.push({
name: x.name,
emoji: `:${x.name}:`,
url: x.url,
isCustomEmoji: true
});
if (x.aliases) {
for (const alias of x.aliases) {
emojiDefinitions.push({
name: alias,
aliasOf: x.name,
emoji: `:${x.name}:`,
url: x.url,
isCustomEmoji: true
});
}
}
}
emojiDefinitions.sort((a, b) => a.name.length - b.name.length);
const emojiDb = markRaw(emojiDefinitions.concat(emjdb));
//#endregion
export default defineComponent({ export default defineComponent({
props: { props: {
type: { type: {
@ -124,7 +155,6 @@ export default defineComponent({
emojis: [], emojis: [],
items: [], items: [],
select: -1, select: -1,
emojiDb: [] as EmojiDef[]
} }
}, },
@ -144,36 +174,6 @@ export default defineComponent({
mounted() { mounted() {
this.setPosition(); this.setPosition();
//#region Construct Emoji DB
const customEmojis = this.$instance.emojis;
const emojiDefinitions: EmojiDef[] = [];
for (const x of customEmojis) {
emojiDefinitions.push({
name: x.name,
emoji: `:${x.name}:`,
url: x.url,
isCustomEmoji: true
});
if (x.aliases) {
for (const alias of x.aliases) {
emojiDefinitions.push({
name: alias,
aliasOf: x.name,
emoji: `:${x.name}:`,
url: x.url,
isCustomEmoji: true
});
}
}
}
emojiDefinitions.sort((a, b) => a.name.length - b.name.length);
this.emojiDb = markRaw(emojiDefinitions.concat(emjdb));
//#endregion
this.textarea.addEventListener('keydown', this.onKeydown); this.textarea.addEventListener('keydown', this.onKeydown);
for (const el of Array.from(document.querySelectorAll('body *'))) { for (const el of Array.from(document.querySelectorAll('body *'))) {
@ -203,6 +203,13 @@ export default defineComponent({
complete(type, value) { complete(type, value) {
this.$emit('done', { type, value }); this.$emit('done', { type, value });
this.$emit('closed'); this.$emit('closed');
if (type === 'emoji') {
let recents = this.$store.state.recentlyUsedEmojis;
recents = recents.filter((e: any) => e !== value);
recents.unshift(value);
this.$store.set('recentlyUsedEmojis', recents.splice(0, 32));
}
}, },
setPosition() { setPosition() {
@ -281,29 +288,26 @@ export default defineComponent({
} }
} else if (this.type == 'emoji') { } else if (this.type == 'emoji') {
if (this.q == null || this.q == '') { if (this.q == null || this.q == '') {
this.emojis = this.emojiDb.filter(x => x.isCustomEmoji && !x.aliasOf).sort((a, b) => { // 使
var textA = a.name.toUpperCase(); this.emojis = this.$store.state.recentlyUsedEmojis.map(emoji => emojiDb.find(e => e.emoji == emoji)).filter(x => x != null);
var textB = b.name.toUpperCase();
return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
});
return; return;
} }
const matched = []; const matched = [];
const max = 30; const max = 30;
this.emojiDb.some(x => { emojiDb.some(x => {
if (x.name.startsWith(this.q) && !x.aliasOf && !matched.some(y => y.emoji == x.emoji)) matched.push(x); if (x.name.startsWith(this.q) && !x.aliasOf && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == max; return matched.length == max;
}); });
if (matched.length < max) { if (matched.length < max) {
this.emojiDb.some(x => { emojiDb.some(x => {
if (x.name.startsWith(this.q) && !matched.some(y => y.emoji == x.emoji)) matched.push(x); if (x.name.startsWith(this.q) && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == max; return matched.length == max;
}); });
} }
if (matched.length < max) { if (matched.length < max) {
this.emojiDb.some(x => { emojiDb.some(x => {
if (x.name.includes(this.q) && !matched.some(y => y.emoji == x.emoji)) matched.push(x); if (x.name.includes(this.q) && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == max; return matched.length == max;
}); });

View file

@ -93,13 +93,13 @@ export default defineComponent({
}); });
return h(this.$store.state.animation ? TransitionGroup : 'div', this.$store.state.animation ? { return h(this.$store.state.animation ? TransitionGroup : 'div', this.$store.state.animation ? {
class: 'sqadhkmv' + (this.noGap ? ' noGap _block' : ''), class: 'sqadhkmv' + (this.noGap ? ' noGap' : ''),
name: 'list', name: 'list',
tag: 'div', tag: 'div',
'data-direction': this.direction, 'data-direction': this.direction,
'data-reversed': this.reversed ? 'true' : 'false', 'data-reversed': this.reversed ? 'true' : 'false',
} : { } : {
class: 'sqadhkmv' + (this.noGap ? ' noGap _block' : ''), class: 'sqadhkmv' + (this.noGap ? ' noGap' : ''),
}, { }, {
default: renderChildren default: renderChildren
}); });

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="yxspomdl" :class="{ inline, colored }"> <div class="yxspomdl" :class="{ inline, colored, mini }">
<div class="ring"></div> <div class="ring"></div>
</div> </div>
</template> </template>
@ -18,7 +18,12 @@ export default defineComponent({
type: Boolean, type: Boolean,
required: false, required: false,
default: true default: true
} },
mini: {
type: Boolean,
required: false,
default: false
},
} }
}); });
</script> </script>
@ -38,6 +43,8 @@ export default defineComponent({
text-align: center; text-align: center;
cursor: wait; cursor: wait;
--size: 48px;
&.colored { &.colored {
color: var(--accent); color: var(--accent);
} }
@ -45,19 +52,12 @@ export default defineComponent({
&.inline { &.inline {
display: inline; display: inline;
padding: 0; padding: 0;
--size: 32px;
}
> .ring:after { &.mini {
width: 32px; padding: 16px;
height: 32px; --size: 32px;
}
> .ring {
&:before,
&:after {
width: 32px;
height: 32px;
}
}
} }
> .ring { > .ring {
@ -70,8 +70,8 @@ export default defineComponent({
content: " "; content: " ";
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;
width: 48px; width: var(--size);
height: 48px; height: var(--size);
border-radius: 50%; border-radius: 50%;
border: solid 4px; border: solid 4px;
} }

View file

@ -1,6 +1,6 @@
<template> <template>
<div <div
class="note _block" class="lxwezrsl _block"
v-if="!muted" v-if="!muted"
v-show="!isDeleted" v-show="!isDeleted"
:tabindex="!isDeleted ? '-1' : null" :tabindex="!isDeleted ? '-1' : null"
@ -67,6 +67,13 @@
<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA> <MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/> <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote != null">RN:</a> <a class="rp" v-if="appearNote.renote != null">RN:</a>
<div class="translation" v-if="translating || translation">
<MkLoading v-if="translating" mini/>
<div class="translated" v-else>
<b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}:</b>
{{ translation.text }}
</div>
</div>
</div> </div>
<div class="files" v-if="appearNote.files.length > 0"> <div class="files" v-if="appearNote.files.length > 0">
<XMediaList :media-list="appearNote.files"/> <XMediaList :media-list="appearNote.files"/>
@ -79,8 +86,8 @@
</div> </div>
<footer class="footer"> <footer class="footer">
<div class="info"> <div class="info">
<span class="mobile" v-if="note.viaMobile"><i class="fas fa-mobile-alt"></i></span> <span class="mobile" v-if="appearNote.viaMobile"><i class="fas fa-mobile-alt"></i></span>
<MkTime class="created-at" :time="note.createdAt" mode="detail"/> <MkTime class="created-at" :time="appearNote.createdAt" mode="detail"/>
</div> </div>
<XReactionsViewer :note="appearNote" ref="reactionsViewer"/> <XReactionsViewer :note="appearNote" ref="reactionsViewer"/>
<button @click="reply()" class="button _button"> <button @click="reply()" class="button _button">
@ -178,6 +185,8 @@ export default defineComponent({
showContent: false, showContent: false,
isDeleted: false, isDeleted: false,
muted: false, muted: false,
translation: null,
translating: false,
}; };
}, },
@ -619,6 +628,11 @@ export default defineComponent({
text: this.$ts.share, text: this.$ts.share,
action: this.share action: this.share
}, },
this.$instance.translatorAvailable ? {
icon: 'fas fa-language',
text: this.$ts.translate,
action: this.translate
} : undefined,
null, null,
statePromise.then(state => state.isFavorited ? { statePromise.then(state => state.isFavorited ? {
icon: 'fas fa-star', icon: 'fas fa-star',
@ -852,6 +866,17 @@ export default defineComponent({
}); });
}, },
async translate() {
if (this.translation != null) return;
this.translating = true;
const res = await os.api('notes/translate', {
noteId: this.appearNote.id,
targetLang: localStorage.getItem('lang') || navigator.language,
});
this.translating = false;
this.translation = res;
},
focus() { focus() {
this.$el.focus(); this.$el.focus();
}, },
@ -874,7 +899,7 @@ export default defineComponent({
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.note { .lxwezrsl {
position: relative; position: relative;
transition: box-shadow 0.1s ease; transition: box-shadow 0.1s ease;
overflow: hidden; overflow: hidden;
@ -1050,6 +1075,13 @@ export default defineComponent({
font-style: oblique; font-style: oblique;
color: var(--renote); color: var(--renote);
} }
> .translation {
border: solid 0.5px var(--divider);
border-radius: var(--radius);
padding: 12px;
margin-top: 8px;
}
} }
> .url-preview { > .url-preview {

View file

@ -51,6 +51,13 @@
<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA> <MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/> <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote != null">RN:</a> <a class="rp" v-if="appearNote.renote != null">RN:</a>
<div class="translation" v-if="translating || translation">
<MkLoading v-if="translating" mini/>
<div class="translated" v-else>
<b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}:</b>
{{ translation.text }}
</div>
</div>
</div> </div>
<div class="files" v-if="appearNote.files.length > 0"> <div class="files" v-if="appearNote.files.length > 0">
<XMediaList :media-list="appearNote.files"/> <XMediaList :media-list="appearNote.files"/>
@ -164,6 +171,8 @@ export default defineComponent({
collapsed: false, collapsed: false,
isDeleted: false, isDeleted: false,
muted: false, muted: false,
translation: null,
translating: false,
}; };
}, },
@ -594,6 +603,11 @@ export default defineComponent({
text: this.$ts.share, text: this.$ts.share,
action: this.share action: this.share
}, },
this.$instance.translatorAvailable ? {
icon: 'fas fa-language',
text: this.$ts.translate,
action: this.translate
} : undefined,
null, null,
statePromise.then(state => state.isFavorited ? { statePromise.then(state => state.isFavorited ? {
icon: 'fas fa-star', icon: 'fas fa-star',
@ -827,6 +841,17 @@ export default defineComponent({
}); });
}, },
async translate() {
if (this.translation != null) return;
this.translating = true;
const res = await os.api('notes/translate', {
noteId: this.appearNote.id,
targetLang: localStorage.getItem('lang') || navigator.language,
});
this.translating = false;
this.translation = res;
},
focus() { focus() {
this.$el.focus(); this.$el.focus();
}, },
@ -1053,6 +1078,13 @@ export default defineComponent({
font-style: oblique; font-style: oblique;
color: var(--renote); color: var(--renote);
} }
> .translation {
border: solid 0.5px var(--divider);
border-radius: var(--radius);
padding: 12px;
margin-top: 8px;
}
} }
> .url-preview { > .url-preview {

View file

@ -9,7 +9,7 @@
<div>{{ $ts.noNotes }}</div> <div>{{ $ts.noNotes }}</div>
</div> </div>
<div v-else> <div v-else class="giivymft" :class="{ noGap }">
<div v-show="more && reversed" style="margin-bottom: var(--margin);"> <div v-show="more && reversed" style="margin-bottom: var(--margin);">
<MkButton style="margin: 0 auto;" @click="fetchMoreFeature" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }"> <MkButton style="margin: 0 auto;" @click="fetchMoreFeature" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<template v-if="!moreFetching">{{ $ts.loadMore }}</template> <template v-if="!moreFetching">{{ $ts.loadMore }}</template>
@ -17,8 +17,8 @@
</MkButton> </MkButton>
</div> </div>
<XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :no-gap="noGap" :ad="true"> <XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :no-gap="noGap" :ad="true" class="notes">
<XNote :note="note" class="_block" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/> <XNote class="qtqtichx" :note="note" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/>
</XList> </XList>
<div v-show="more && !reversed" style="margin-top: var(--margin);"> <div v-show="more && !reversed" style="margin-top: var(--margin);">
@ -108,4 +108,21 @@ export default defineComponent({
.fade-leave-to { .fade-leave-to {
opacity: 0; opacity: 0;
} }
.giivymft {
&.noGap {
> .notes {
background: var(--panel);
}
}
&:not(.noGap) {
> .notes {
.qtqtichx {
background: var(--panel);
border-radius: var(--radius);
}
}
}
}
</style> </style>

View file

@ -17,7 +17,7 @@
<span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span> <span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span>
<span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span> <span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span>
</button> </button>
<button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button> <button class="submit _buttonPrimary" :disabled="!canPost" @click="post" data-cy-open-post-form-submit>{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button>
</div> </div>
</header> </header>
<div class="form" :class="{ fixed }"> <div class="form" :class="{ fixed }">
@ -36,7 +36,7 @@
</div> </div>
<MkInfo warn v-if="hasNotSpecifiedMentions" class="hasNotSpecifiedMentions">{{ $ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ $ts.add }}</button></MkInfo> <MkInfo warn v-if="hasNotSpecifiedMentions" class="hasNotSpecifiedMentions">{{ $ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ $ts.add }}</button></MkInfo>
<input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$ts.annotation" @keydown="onKeydown"> <input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$ts.annotation" @keydown="onKeydown">
<textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd" /> <textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd" data-cy-post-form-text/>
<input v-show="withHashtags" ref="hashtags" class="hashtags" v-model="hashtags" :placeholder="$ts.hashtags" list="hashtags"> <input v-show="withHashtags" ref="hashtags" class="hashtags" v-model="hashtags" :placeholder="$ts.hashtags" list="hashtags">
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/> <XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/> <XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>

View file

@ -3,11 +3,11 @@
<div class="auth _section"> <div class="auth _section">
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div> <div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
<div class="normal-signin" v-if="!totpLogin"> <div class="normal-signin" v-if="!totpLogin">
<MkInput v-model="username" :placeholder="$ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:modelValue="onUsernameChange"> <MkInput v-model="username" :placeholder="$ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:modelValue="onUsernameChange" data-cy-signin-username>
<template #prefix>@</template> <template #prefix>@</template>
<template #suffix>@{{ host }}</template> <template #suffix>@{{ host }}</template>
</MkInput> </MkInput>
<MkInput v-model="password" :placeholder="$ts.password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required> <MkInput v-model="password" :placeholder="$ts.password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required data-cy-signin-password>
<template #prefix><i class="fas fa-lock"></i></template> <template #prefix><i class="fas fa-lock"></i></template>
<template #caption><button class="_textButton" @click="resetPassword" type="button">{{ $ts.forgotPassword }}</button></template> <template #caption><button class="_textButton" @click="resetPassword" type="button">{{ $ts.forgotPassword }}</button></template>
</MkInput> </MkInput>

View file

@ -5,7 +5,7 @@
<template #label>{{ $ts.invitationCode }}</template> <template #label>{{ $ts.invitationCode }}</template>
<template #prefix><i class="fas fa-key"></i></template> <template #prefix><i class="fas fa-key"></i></template>
</MkInput> </MkInput>
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:modelValue="onChangeUsername"> <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:modelValue="onChangeUsername" data-cy-signup-username>
<template #label>{{ $ts.username }}</template> <template #label>{{ $ts.username }}</template>
<template #prefix>@</template> <template #prefix>@</template>
<template #suffix>@{{ host }}</template> <template #suffix>@{{ host }}</template>
@ -19,7 +19,7 @@
<span v-if="usernameState == 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span> <span v-if="usernameState == 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span>
</template> </template>
</MkInput> </MkInput>
<MkInput v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword"> <MkInput v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword" data-cy-signup-password>
<template #label>{{ $ts.password }}</template> <template #label>{{ $ts.password }}</template>
<template #prefix><i class="fas fa-lock"></i></template> <template #prefix><i class="fas fa-lock"></i></template>
<template #caption> <template #caption>
@ -28,7 +28,7 @@
<span v-if="passwordStrength == 'high'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.strongPassword }}</span> <span v-if="passwordStrength == 'high'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.strongPassword }}</span>
</template> </template>
</MkInput> </MkInput>
<MkInput v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePasswordRetype"> <MkInput v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePasswordRetype" data-cy-signup-password-retype>
<template #label>{{ $ts.password }} ({{ $ts.retype }})</template> <template #label>{{ $ts.password }} ({{ $ts.retype }})</template>
<template #prefix><i class="fas fa-lock"></i></template> <template #prefix><i class="fas fa-lock"></i></template>
<template #caption> <template #caption>
@ -46,7 +46,7 @@
</label> </label>
<captcha v-if="meta.enableHcaptcha" class="captcha" provider="hcaptcha" ref="hcaptcha" v-model:value="hCaptchaResponse" :sitekey="meta.hcaptchaSiteKey"/> <captcha v-if="meta.enableHcaptcha" class="captcha" provider="hcaptcha" ref="hcaptcha" v-model:value="hCaptchaResponse" :sitekey="meta.hcaptchaSiteKey"/>
<captcha v-if="meta.enableRecaptcha" class="captcha" provider="recaptcha" ref="recaptcha" v-model:value="reCaptchaResponse" :sitekey="meta.recaptchaSiteKey"/> <captcha v-if="meta.enableRecaptcha" class="captcha" provider="recaptcha" ref="recaptcha" v-model:value="reCaptchaResponse" :sitekey="meta.recaptchaSiteKey"/>
<MkButton type="submit" :disabled="shouldDisableSubmitting" primary>{{ $ts.start }}</MkButton> <MkButton type="submit" :disabled="shouldDisableSubmitting" primary data-cy-signup-submit>{{ $ts.start }}</MkButton>
</template> </template>
</form> </form>
</template> </template>

View file

@ -1,5 +1,5 @@
<template> <template>
<transition :name="$store.state.animation ? 'popup-menu' : ''" :duration="$store.state.animation ? 300 : 0" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered"> <transition :name="$store.state.animation ? 'popup-menu' : ''" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered">
<div v-show="manualShowing != null ? manualShowing : showing" class="ccczpooj" :class="{ front, fixed, top: position === 'top' }" ref="content" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> <div v-show="manualShowing != null ? manualShowing : showing" class="ccczpooj" :class="{ front, fixed, top: position === 'top' }" ref="content" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<slot :point="point"></slot> <slot :point="point"></slot>
</div> </div>

View file

@ -0,0 +1,58 @@
<template>
<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="ewlycnyt">
<div class="title">{{ $ts.misskeyUpdated }}</div>
<div class="version">{{ version }}🚀</div>
<MkButton full @click="whatIsNew">{{ $ts.whatIsNew }}</MkButton>
<MkButton primary full @click="$refs.modal.close()">{{ $ts.gotIt }}</MkButton>
</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 { version } from '@client/config';
export default defineComponent({
components: {
MkModal,
MkButton,
},
data() {
return {
version: version,
};
},
methods: {
whatIsNew() {
this.$refs.modal.close();
this.$router.push('/docs/general/changelog');
}
}
});
</script>
<style lang="scss" scoped>
.ewlycnyt {
position: relative;
padding: 32px;
min-width: 320px;
max-width: 480px;
box-sizing: border-box;
text-align: center;
background: var(--panel);
border-radius: var(--radius);
> .title {
font-weight: bold;
}
> .version {
margin: 1em 0;
}
}
</style>

View file

@ -16,6 +16,7 @@ if (localStorage.getItem('accounts') != null) {
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { Integrations } from '@sentry/tracing'; import { Integrations } from '@sentry/tracing';
import { computed, createApp, watch, markRaw } from 'vue'; import { computed, createApp, watch, markRaw } from 'vue';
import compareVersions from 'compare-versions';
import widgets from '@client/widgets'; import widgets from '@client/widgets';
import directives from '@client/directives'; import directives from '@client/directives';
@ -25,7 +26,7 @@ import { router } from '@client/router';
import { applyTheme } from '@client/scripts/theme'; import { applyTheme } from '@client/scripts/theme';
import { isDeviceDarkmode } from '@client/scripts/is-device-darkmode'; import { isDeviceDarkmode } from '@client/scripts/is-device-darkmode';
import { i18n } from '@client/i18n'; import { i18n } from '@client/i18n';
import { stream, dialog, post } from '@client/os'; import { stream, dialog, post, popup } from '@client/os';
import * as sound from '@client/scripts/sound'; import * as sound from '@client/scripts/sound';
import { $i, refreshAccount, login, updateAccount, signout } from '@client/account'; import { $i, refreshAccount, login, updateAccount, signout } from '@client/account';
import { defaultStore, ColdDeviceStorage } from '@client/store'; import { defaultStore, ColdDeviceStorage } from '@client/store';
@ -227,6 +228,23 @@ if (splash) {
splash.style.pointerEvents = 'none'; splash.style.pointerEvents = 'none';
} }
// クライアントが更新されたか?
const lastVersion = localStorage.getItem('lastVersion');
if (lastVersion !== version) {
localStorage.setItem('lastVersion', version);
// テーマリビルドするため
localStorage.removeItem('theme');
try { // 変なバージョン文字列来るとcompareVersionsでエラーになるため
if (lastVersion != null && compareVersions(version, lastVersion) === 1) {
popup(import('@client/components/updated.vue'), {}, {}, 'closed');
}
} catch (e) {
}
}
// NOTE: この処理は必ず↑のクライアント更新時処理より後に来ること(テーマ再構築のため)
watch(defaultStore.reactiveState.darkMode, (darkMode) => { watch(defaultStore.reactiveState.darkMode, (darkMode) => {
applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme'));
}, { immediate: localStorage.theme == null }); }, { immediate: localStorage.theme == null });

View file

@ -25,6 +25,7 @@ export async function fetchInstance() {
} }
export const emojiCategories = computed(() => { export const emojiCategories = computed(() => {
if (instance.emojis == null) return [];
const categories = new Set(); const categories = new Set();
for (const emoji of instance.emojis) { for (const emoji of instance.emojis) {
categories.add(emoji.category); categories.add(emoji.category);
@ -33,6 +34,7 @@ export const emojiCategories = computed(() => {
}); });
export const emojiTags = computed(() => { export const emojiTags = computed(() => {
if (instance.emojis == null) return [];
const tags = new Set(); const tags = new Set();
for (const emoji of instance.emojis) { for (const emoji of instance.emojis) {
for (const tag of emoji.aliases) { for (const tag of emoji.aliases) {

View file

@ -4,14 +4,14 @@
<div id="debug"></div> <div id="debug"></div>
<section class="_formItem about"> <section class="_formItem about">
<div class="_formPanel panel" :class="{ playing: easterEggEngine != null }" ref="about"> <div class="_formPanel panel" :class="{ playing: easterEggEngine != null }" ref="about">
<img src="/static-assets/client/about-icon.png" alt="" class="icon" ref="icon" @load="iconLoaded" draggable="false"/> <img src="/static-assets/client/about-icon.png" alt="" class="icon" @load="iconLoaded" draggable="false" @click="gravity"/>
<div class="misskey">Misskey</div> <div class="misskey">Misskey</div>
<div class="version">v{{ version }}</div> <div class="version">v{{ version }}</div>
<span class="emoji" v-for="emoji in easterEggEmojis" :key="emoji.id" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :custom-emojis="$instance.emojis" :is-reaction="false" :normal="true" :no-style="true"/></span> <span class="emoji" v-for="emoji in easterEggEmojis" :key="emoji.id" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :custom-emojis="$instance.emojis" :is-reaction="false" :normal="true" :no-style="true"/></span>
</div> </div>
</section> </section>
<section class="_formItem" style="text-align: center; padding: 0 16px;" @click="gravity"> <section class="_formItem" style="text-align: center; padding: 0 16px;">
{{ $ts._aboutMisskey.about }} {{ $ts._aboutMisskey.about }}<br><MkA class="_link" to="/docs/general/misskey">{{ $ts.learnMore }}</MkA>
</section> </section>
<FormGroup> <FormGroup>
<FormLink to="https://github.com/misskey-dev/misskey" external> <FormLink to="https://github.com/misskey-dev/misskey" external>
@ -54,7 +54,6 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import VanillaTilt from 'vanilla-tilt';
import { version } from '@client/config'; import { version } from '@client/config';
import FormLink from '@client/components/form/link.vue'; import FormLink from '@client/components/form/link.vue';
import FormBase from '@client/components/form/base.vue'; import FormBase from '@client/components/form/base.vue';
@ -62,7 +61,6 @@ import FormGroup from '@client/components/form/group.vue';
import FormKeyValueView from '@client/components/form/key-value-view.vue'; import FormKeyValueView from '@client/components/form/key-value-view.vue';
import MkLink from '@client/components/link.vue'; import MkLink from '@client/components/link.vue';
import { physics } from '@client/scripts/physics.ts'; import { physics } from '@client/scripts/physics.ts';
import * as os from '@client/os';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';
const patrons = [ const patrons = [
@ -145,15 +143,6 @@ export default defineComponent({
} }
}, },
mounted() {
VanillaTilt.init(this.$refs.icon, {
max: 30,
perspective: 500,
scale: 1.125,
speed: 1000,
});
},
beforeUnmount() { beforeUnmount() {
if (this.easterEggEngine) { if (this.easterEggEngine) {
this.easterEggEngine.stop(); this.easterEggEngine.stop();
@ -181,7 +170,6 @@ export default defineComponent({
gravity() { gravity() {
if (!this.easterEggReady) return; if (!this.easterEggReady) return;
this.easterEggReady = false; this.easterEggReady = false;
this.$refs.icon.vanillaTilt.destroy();
this.easterEggEngine = physics(this.$refs.about); this.easterEggEngine = physics(this.$refs.about);
} }
} }

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="_root"> <div class="_root">
<div class="_block" style="padding: 24px;"> <div class="_block" style="padding: 24px;">
<MkInput v-model="endpoint" :datalist="endpoints" @update:modelValue="onEndpointChange()"> <MkInput v-model="endpoint" :datalist="endpoints" @update:modelValue="onEndpointChange()" class="_inputNoTopMargin">
<template #label>Endpoint</template> <template #label>Endpoint</template>
</MkInput> </MkInput>
<MkTextarea v-model="body" code> <MkTextarea v-model="body" code>

View file

@ -1,50 +1,54 @@
<template> <template>
<div class="vtaihdtm"> <div class="vtaihdtm">
<div class="search"> <div class="body">
<MkInput v-model="query" :debounce="true" type="search" class="_inputNoTopMargin _inputNoBottomMargin" :placeholder="$ts.search"> <div class="search">
<template #prefix><i class="fas fa-search"></i></template> <MkInput v-model="query" :debounce="true" type="search" class="_inputNoTopMargin _inputNoBottomMargin" :placeholder="$ts.search">
</MkInput> <template #prefix><i class="fas fa-search"></i></template>
</MkInput>
</div>
<div class="list">
<MkFolder>
<template #header>{{ $ts._docs.generalTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('general/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.features }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('features/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.advancedTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('advanced/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.admin }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('admin/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
</div>
</div> </div>
<MkFolder>
<template #header>{{ $ts._docs.generalTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('general/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.features }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('features/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.advancedTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('advanced/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.admin }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('admin/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
</div> </div>
</template> </template>
@ -97,41 +101,50 @@ export default defineComponent({
.vtaihdtm { .vtaihdtm {
background: var(--panel); background: var(--panel);
> .search { > .body {
padding: 16px; max-width: 900px;
} margin: 0 auto;
.docs { > .search {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
grid-gap: 12px;
margin: 0 16px 16px 16px;
> .doc {
display: inline-block;
padding: 16px; padding: 16px;
border: solid 1px var(--divider); }
border-radius: 6px;
&:hover { > .list {
border: solid 1px var(--accent); padding: 0 16px;
text-decoration: none;
}
> .title { .docs {
font-weight: bold; display: grid;
} grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
grid-gap: 12px;
margin: 0 0 16px 0;
> .summary { > .doc {
white-space: nowrap; display: inline-block;
overflow: hidden; padding: 16px;
text-overflow: ellipsis; border: solid 1px var(--divider);
font-size: 0.9em; border-radius: 6px;
}
> .read { &:hover {
color: var(--link); border: solid 1px var(--accent);
font-size: 0.9em; text-decoration: none;
}
> .title {
font-weight: bold;
}
> .summary {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.9em;
}
> .read {
color: var(--link);
font-size: 0.9em;
}
}
} }
} }
} }

View file

@ -1,6 +1,8 @@
<template> <template>
<div class="_section"> <div class="jmelgwjh">
<XNotes class="_content" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/> <div class="body">
<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
</div>
</div> </div>
</template> </template>
@ -42,3 +44,16 @@ export default defineComponent({
} }
}); });
</script> </script>
<style lang="scss" scoped>
.jmelgwjh {
background: var(--bg);
> .body {
box-sizing: border-box;
max-width: 800px;
margin: 0 auto;
padding: 16px;
}
}
</style>

View file

@ -93,10 +93,8 @@ export default defineComponent({
}); });
if (canceled) return; if (canceled) return;
os.api('drive/files/delete', { os.apiWithDialog('drive/files/delete', {
fileId: this.file.id fileId: this.file.id
}).then(() => {
this.$refs.files.removeItem(x => x.id === this.file.id);
}); });
}, },

View file

@ -7,7 +7,12 @@
Summaly Proxy URL Summaly Proxy URL
</FormInput> </FormInput>
</FormGroup> </FormGroup>
<FormGroup>
<FormInput v-model:value="deeplAuthKey">
<template #prefix><i class="fas fa-key"></i></template>
DeepL Auth Key
</FormInput>
</FormGroup>
<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton> <FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
</FormSuspense> </FormSuspense>
</FormBase> </FormBase>
@ -44,6 +49,7 @@ export default defineComponent({
icon: 'fas fa-cogs' icon: 'fas fa-cogs'
}, },
summalyProxy: '', summalyProxy: '',
deeplAuthKey: '',
} }
}, },
@ -55,10 +61,12 @@ export default defineComponent({
async init() { async init() {
const meta = await os.api('meta', { detail: true }); const meta = await os.api('meta', { detail: true });
this.summalyProxy = meta.summalyProxy; this.summalyProxy = meta.summalyProxy;
this.deeplAuthKey = meta.deeplAuthKey;
}, },
save() { save() {
os.apiWithDialog('admin/update-meta', { os.apiWithDialog('admin/update-meta', {
summalyProxy: this.summalyProxy, summalyProxy: this.summalyProxy,
deeplAuthKey: this.deeplAuthKey,
}).then(() => { }).then(() => {
fetchInstance(); fetchInstance();
}); });

View file

@ -8,9 +8,9 @@
<div class="main _gap"> <div class="main _gap">
<MkButton v-if="!showNext && hasNext" class="load next" @click="showNext = true"><i class="fas fa-chevron-up"></i></MkButton> <MkButton v-if="!showNext && hasNext" class="load next" @click="showNext = true"><i class="fas fa-chevron-up"></i></MkButton>
<div class="_content _gap"> <div class="note _gap">
<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_gap"/> <MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_isolated"/>
<XNoteDetailed v-model:note="note" :key="note.id" class="_gap"/> <XNoteDetailed v-model:note="note" :key="note.id" class="_isolated note"/>
</div> </div>
<div class="_content clips _gap" v-if="clips && clips.length > 0"> <div class="_content clips _gap" v-if="clips && clips.length > 0">
<div class="title">{{ $ts.clip }}</div> <div class="title">{{ $ts.clip }}</div>
@ -108,6 +108,7 @@ export default defineComponent({
os.api('notes/show', { os.api('notes/show', {
noteId: this.noteId noteId: this.noteId
}).then(note => { }).then(note => {
this.note = note;
Promise.all([ Promise.all([
os.api('notes/clips', { os.api('notes/clips', {
noteId: note.id, noteId: note.id,
@ -126,7 +127,6 @@ export default defineComponent({
this.clips = clips; this.clips = clips;
this.hasPrev = prev.length !== 0; this.hasPrev = prev.length !== 0;
this.hasNext = next.length !== 0; this.hasNext = next.length !== 0;
this.note = note;
}); });
}).catch(e => { }).catch(e => {
this.error = e; this.error = e;
@ -147,6 +147,8 @@ export default defineComponent({
} }
.fcuexfpr { .fcuexfpr {
background: var(--bg);
> .note { > .note {
> .main { > .main {
> .load { > .load {
@ -163,6 +165,13 @@ export default defineComponent({
} }
} }
> .note {
> .note {
border-radius: var(--radius);
background: var(--panel);
}
}
> .clips { > .clips {
> .title { > .title {
font-weight: bold; font-weight: bold;

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="_root"> <div class="">
<XNotifications class="_content" @before="before" @after="after" page/> <XNotifications class="_content" @before="before" @after="after" page/>
</div> </div>
</template> </template>

View file

@ -48,6 +48,7 @@ const soundsTypes = [
'syuilo/ryukyu', 'syuilo/ryukyu',
'syuilo/kick', 'syuilo/kick',
'syuilo/snare', 'syuilo/snare',
'syuilo/queue-jammed',
'aisha/1', 'aisha/1',
'aisha/2', 'aisha/2',
'aisha/3', 'aisha/3',

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="cmuxhskf _root" v-hotkey.global="keymap"> <div class="cmuxhskf" v-hotkey.global="keymap">
<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block _isolated"/> <XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block _isolated"/>
<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block _isolated" fixed/> <XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block _isolated" fixed/>
<div class="tabs"> <div class="tabs">
@ -19,7 +19,7 @@
</div> </div>
</div> </div>
<div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div> <div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
<XTimeline ref="tl" <XTimeline ref="tl" class="tl"
:key="src === 'list' ? `list:${list.id}` : src === 'antenna' ? `antenna:${antenna.id}` : src === 'channel' ? `channel:${channel.id}` : src" :key="src === 'list' ? `list:${list.id}` : src === 'antenna' ? `antenna:${antenna.id}` : src === 'channel' ? `channel:${channel.id}` : src"
:src="src" :src="src"
:list="list ? list.id : null" :list="list ? list.id : null"
@ -211,8 +211,6 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.cmuxhskf { .cmuxhskf {
background: var(--bg);
> .new { > .new {
position: sticky; position: sticky;
top: calc(var(--stickyTop, 0px) + 16px); top: calc(var(--stickyTop, 0px) + 16px);
@ -262,10 +260,9 @@ export default defineComponent({
left: 0; left: 0;
right: 0; right: 0;
margin: 0 auto; margin: 0 auto;
width: calc(100% - 16px); width: 100%;
height: 4px; height: 2px;
background: var(--accent); background: var(--accent);
border-radius: 8px 8px 0 0;
} }
} }
@ -289,5 +286,9 @@ export default defineComponent({
} }
} }
} }
> .tl {
border-top: solid 0.5px var(--divider);
}
} }
</style> </style>

View file

@ -27,8 +27,8 @@
<div class="desc" v-html="meta.description || $ts.headlineMisskey"></div> <div class="desc" v-html="meta.description || $ts.headlineMisskey"></div>
</div> </div>
<div class="action"> <div class="action">
<MkButton @click="signup()" inline primary>{{ $ts.signup }}</MkButton> <MkButton @click="signup()" inline primary data-cy-signup>{{ $ts.signup }}</MkButton>
<MkButton @click="signin()" inline>{{ $ts.login }}</MkButton> <MkButton @click="signin()" inline data-cy-signin>{{ $ts.login }}</MkButton>
</div> </div>
<div class="status" v-if="onlineUsersCount && stats"> <div class="status" v-if="onlineUsersCount && stats">
<div> <div>

View file

@ -3,17 +3,19 @@
<h1>Welcome to Misskey!</h1> <h1>Welcome to Misskey!</h1>
<div> <div>
<p>{{ $ts.intro }}</p> <p>{{ $ts.intro }}</p>
<MkInput v-model="username" pattern="^[a-zA-Z0-9_]{1,20}$" spellcheck="false" required> <MkInput v-model="username" pattern="^[a-zA-Z0-9_]{1,20}$" spellcheck="false" required data-cy-admin-username>
<template #label>{{ $ts.username }}</template> <template #label>{{ $ts.username }}</template>
<template #prefix>@</template> <template #prefix>@</template>
<template #suffix>@{{ host }}</template> <template #suffix>@{{ host }}</template>
</MkInput> </MkInput>
<MkInput v-model="password" type="password"> <MkInput v-model="password" type="password" data-cy-admin-password>
<template #label>{{ $ts.password }}</template> <template #label>{{ $ts.password }}</template>
<template #prefix><i class="fas fa-lock"></i></template> <template #prefix><i class="fas fa-lock"></i></template>
</MkInput> </MkInput>
<footer> <footer>
<MkButton primary type="submit" :disabled="submitting">{{ submitting ? $ts.processing : $ts.done }}<MkEllipsis v-if="submitting"/></MkButton> <MkButton primary type="submit" :disabled="submitting" data-cy-admin-ok>
{{ submitting ? $ts.processing : $ts.done }}<MkEllipsis v-if="submitting"/>
</MkButton>
</footer> </footer>
</div> </div>
</form> </form>

View file

@ -2,6 +2,23 @@ import { ColdDeviceStorage } from '@client/store';
const cache = new Map<string, HTMLAudioElement>(); const cache = new Map<string, HTMLAudioElement>();
export function getAudio(file: string, useCache = true): HTMLAudioElement {
let audio: HTMLAudioElement;
if (useCache && cache.has(file)) {
audio = cache.get(file);
} else {
audio = new Audio(`/static-assets/client/sounds/${file}.mp3`);
if (useCache) cache.set(file, audio);
}
return audio;
}
export function setVolume(audio: HTMLAudioElement, volume: number): HTMLAudioElement {
const masterVolume = ColdDeviceStorage.get('sound_masterVolume');
audio.volume = masterVolume - ((1 - volume) * masterVolume);
return audio;
}
export function play(type: string) { export function play(type: string) {
const sound = ColdDeviceStorage.get('sound_' + type as any); const sound = ColdDeviceStorage.get('sound_' + type as any);
if (sound.type == null) return; if (sound.type == null) return;
@ -12,13 +29,6 @@ export function playFile(file: string, volume: number) {
const masterVolume = ColdDeviceStorage.get('sound_masterVolume'); const masterVolume = ColdDeviceStorage.get('sound_masterVolume');
if (masterVolume === 0) return; if (masterVolume === 0) return;
let audio: HTMLAudioElement; const audio = setVolume(getAudio(file), volume);
if (cache.has(file)) {
audio = cache.get(file);
} else {
audio = new Audio(`/static-assets/client/sounds/${file}.mp3`);
cache.set(file, audio);
}
audio.volume = masterVolume - ((1 - volume) * masterVolume);
audio.play(); audio.play();
} }

View file

@ -330,6 +330,7 @@ hr {
contain: layout; // ふき出しがボックスから飛び出て表示されるようなデザインをする場合もあるので paint contain することができない contain: layout; // ふき出しがボックスから飛び出て表示されるようなデザインをする場合もあるので paint contain することができない
} }
// TODO: 廃止
._root { ._root {
box-sizing: border-box; box-sizing: border-box;
margin: var(--root-margin, 32px) auto; margin: var(--root-margin, 32px) auto;

View file

@ -2,7 +2,7 @@
<div class="fdidabkb" :class="{ center }" :style="`--height:${height};`" :key="key"> <div class="fdidabkb" :class="{ center }" :style="`--height:${height};`" :key="key">
<transition :name="$store.state.animation ? 'header' : ''" mode="out-in" appear> <transition :name="$store.state.animation ? 'header' : ''" mode="out-in" appear>
<div class="buttons left" v-if="backButton"> <div class="buttons left" v-if="backButton">
<button class="_button button back" @click.stop="$emit('back')" v-tooltip="$ts.goBack"><i class="fas fa-chevron-left"></i></button> <button class="_button button back" @click.stop="$emit('back')" @touchstart="preventDrag" v-tooltip="$ts.goBack"><i class="fas fa-chevron-left"></i></button>
</div> </div>
</transition> </transition>
<template v-if="info"> <template v-if="info">
@ -20,10 +20,10 @@
</div> </div>
<div class="buttons right"> <div class="buttons right">
<template v-if="info.actions && showActions"> <template v-if="info.actions && showActions">
<button v-for="action in info.actions" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" v-tooltip="action.text"><i :class="action.icon"></i></button> <button v-for="action in info.actions" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag" v-tooltip="action.text"><i :class="action.icon"></i></button>
</template> </template>
<button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button> <button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" @touchstart="preventDrag" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button>
<button v-if="closeButton" class="_button button" @click.stop="$emit('close')" v-tooltip="$ts.close"><i class="fas fa-times"></i></button> <button v-if="closeButton" class="_button button" @click.stop="$emit('close')" @touchstart="preventDrag" v-tooltip="$ts.close"><i class="fas fa-times"></i></button>
</div> </div>
</template> </template>
</div> </div>
@ -122,6 +122,10 @@ export default defineComponent({
menu = menu.concat(this.menu); menu = menu.concat(this.menu);
} }
popupMenu(menu, ev.currentTarget || ev.target); popupMenu(menu, ev.currentTarget || ev.target);
},
preventDrag(ev) {
ev.stopPropagation();
} }
} }
}); });

View file

@ -3,7 +3,7 @@
<button class="item _button account" @click="openAccountMenu" v-click-anime> <button class="item _button account" @click="openAccountMenu" v-click-anime>
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/> <MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
</button> </button>
<div class="post" @click="post"> <div class="post" @click="post" data-cy-open-post-form>
<MkButton class="button" primary full> <MkButton class="button" primary full>
<i class="fas fa-pencil-alt fa-fw"></i><span class="text" v-if="!iconOnly">{{ $ts.note }}</span> <i class="fas fa-pencil-alt fa-fw"></i><span class="text" v-if="!iconOnly">{{ $ts.note }}</span>
</MkButton> </MkButton>

View file

@ -4,7 +4,7 @@
<div class="contents" ref="contents" @contextmenu.stop="onContextmenu"> <div class="contents" ref="contents" @contextmenu.stop="onContextmenu">
<header class="header" ref="header" @click="onHeaderClick"> <header class="header" ref="header" @click="onHeaderClick">
<XHeader :info="pageInfo"/> <XHeader :info="pageInfo" :back-button="true" @back="back()"/>
</header> </header>
<main ref="main"> <main ref="main">
<div class="content"> <div class="content">
@ -175,6 +175,10 @@ export default defineComponent({
window.scroll({ top: 0, behavior: 'smooth' }); window.scroll({ top: 0, behavior: 'smooth' });
}, },
back() {
history.back();
},
onTransition() { onTransition() {
if (window._scroll) window._scroll(); if (window._scroll) window._scroll();
}, },
@ -253,11 +257,16 @@ export default defineComponent({
//backdrop-filter: var(--blur, blur(4px)); //backdrop-filter: var(--blur, blur(4px));
} }
> .sidebar {
border-right: solid 0.5px var(--divider);
}
> .contents { > .contents {
width: 100%; width: 100%;
min-width: 0; min-width: 0;
--stickyTop: #{$header-height}; --stickyTop: #{$header-height};
padding-top: $header-height; padding-top: $header-height;
background: var(--panel);
> .header { > .header {
position: fixed; position: fixed;
@ -272,7 +281,7 @@ export default defineComponent({
-webkit-backdrop-filter: var(--blur, blur(32px)); -webkit-backdrop-filter: var(--blur, blur(32px));
backdrop-filter: var(--blur, blur(32px)); backdrop-filter: var(--blur, blur(32px));
background-color: var(--header); background-color: var(--header);
//border-bottom: solid 0.5px var(--divider); border-bottom: solid 0.5px var(--divider);
user-select: none; user-select: none;
} }

View file

@ -50,6 +50,7 @@ import { defineComponent, markRaw } from 'vue';
import define from './define'; import define from './define';
import * as os from '@client/os'; import * as os from '@client/os';
import number from '@client/filters/number'; import number from '@client/filters/number';
import * as sound from '@client/scripts/sound';
const widget = define({ const widget = define({
name: 'jobQueue', name: 'jobQueue',
@ -58,6 +59,10 @@ const widget = define({
type: 'boolean', type: 'boolean',
default: false, default: false,
}, },
sound: {
type: 'boolean',
default: false,
},
}) })
}); });
@ -79,6 +84,7 @@ export default defineComponent({
delayed: 0, delayed: 0,
}, },
prev: {}, prev: {},
sound: sound.setVolume(sound.getAudio('syuilo/queue-jammed'), 1)
}; };
}, },
created() { created() {
@ -107,6 +113,10 @@ export default defineComponent({
this[domain].active = stats[domain].active; this[domain].active = stats[domain].active;
this[domain].waiting = stats[domain].waiting; this[domain].waiting = stats[domain].waiting;
this[domain].delayed = stats[domain].delayed; this[domain].delayed = stats[domain].delayed;
if (this[domain].waiting > 0 && this.props.sound && this.sound.paused) {
this.sound.play();
}
} }
}, },

View file

@ -3,14 +3,20 @@
*/ */
import * as fs from 'fs'; import * as fs from 'fs';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import * as yaml from 'js-yaml'; import * as yaml from 'js-yaml';
import { Source, Mixin } from './types'; import { Source, Mixin } from './types';
const meta = require('../meta.json'); import * as meta from '../meta.json';
//const _filename = fileURLToPath(import.meta.url);
const _filename = __filename;
const _dirname = dirname(_filename);
/** /**
* Path of configuration directory * Path of configuration directory
*/ */
const dir = `${__dirname}/../../.config`; const dir = `${_dirname}/../../.config`;
/** /**
* Path of configuration file * Path of configuration file

View file

@ -1,7 +1,7 @@
// TODO: 消したい // TODO: 消したい
const interval = 30 * 60 * 1000; const interval = 30 * 60 * 1000;
import { AttestationChallenges } from '../models'; import { AttestationChallenges } from '@/models/index';
import { LessThan } from 'typeorm'; import { LessThan } from 'typeorm';
/** /**

View file

@ -1,5 +1,5 @@
import * as elasticsearch from '@elastic/elasticsearch'; import * as elasticsearch from '@elastic/elasticsearch';
import config from '@/config'; import config from '@/config/index';
const index = { const index = {
settings: { settings: {

View file

@ -1,3 +1,3 @@
import Logger from '../services/logger'; import Logger from '@/services/logger';
export const dbLogger = new Logger('db'); export const dbLogger = new Logger('db');

View file

@ -3,74 +3,74 @@ const types = require('pg').types;
types.setTypeParser(20, Number); types.setTypeParser(20, Number);
import { createConnection, Logger, getConnection } from 'typeorm'; import { createConnection, Logger, getConnection } from 'typeorm';
import config from '@/config'; import config from '@/config/index';
import { entities as charts } from '../services/chart/entities'; import { entities as charts } from '@/services/chart/entities';
import { dbLogger } from './logger'; import { dbLogger } from './logger';
import * as highlight from 'cli-highlight'; import * as highlight from 'cli-highlight';
import { Log } from '../models/entities/log'; import { Log } from '@/models/entities/log';
import { User } from '../models/entities/user'; import { User } from '@/models/entities/user';
import { DriveFile } from '../models/entities/drive-file'; import { DriveFile } from '@/models/entities/drive-file';
import { DriveFolder } from '../models/entities/drive-folder'; import { DriveFolder } from '@/models/entities/drive-folder';
import { AccessToken } from '../models/entities/access-token'; import { AccessToken } from '@/models/entities/access-token';
import { App } from '../models/entities/app'; import { App } from '@/models/entities/app';
import { PollVote } from '../models/entities/poll-vote'; import { PollVote } from '@/models/entities/poll-vote';
import { Note } from '../models/entities/note'; import { Note } from '@/models/entities/note';
import { NoteReaction } from '../models/entities/note-reaction'; import { NoteReaction } from '@/models/entities/note-reaction';
import { NoteWatching } from '../models/entities/note-watching'; import { NoteWatching } from '@/models/entities/note-watching';
import { NoteUnread } from '../models/entities/note-unread'; import { NoteUnread } from '@/models/entities/note-unread';
import { Notification } from '../models/entities/notification'; import { Notification } from '@/models/entities/notification';
import { Meta } from '../models/entities/meta'; import { Meta } from '@/models/entities/meta';
import { Following } from '../models/entities/following'; import { Following } from '@/models/entities/following';
import { Instance } from '../models/entities/instance'; import { Instance } from '@/models/entities/instance';
import { Muting } from '../models/entities/muting'; import { Muting } from '@/models/entities/muting';
import { SwSubscription } from '../models/entities/sw-subscription'; import { SwSubscription } from '@/models/entities/sw-subscription';
import { Blocking } from '../models/entities/blocking'; import { Blocking } from '@/models/entities/blocking';
import { UserList } from '../models/entities/user-list'; import { UserList } from '@/models/entities/user-list';
import { UserListJoining } from '../models/entities/user-list-joining'; import { UserListJoining } from '@/models/entities/user-list-joining';
import { UserGroup } from '../models/entities/user-group'; import { UserGroup } from '@/models/entities/user-group';
import { UserGroupJoining } from '../models/entities/user-group-joining'; import { UserGroupJoining } from '@/models/entities/user-group-joining';
import { UserGroupInvitation } from '../models/entities/user-group-invitation'; import { UserGroupInvitation } from '@/models/entities/user-group-invitation';
import { Hashtag } from '../models/entities/hashtag'; import { Hashtag } from '@/models/entities/hashtag';
import { NoteFavorite } from '../models/entities/note-favorite'; import { NoteFavorite } from '@/models/entities/note-favorite';
import { AbuseUserReport } from '../models/entities/abuse-user-report'; import { AbuseUserReport } from '@/models/entities/abuse-user-report';
import { RegistrationTicket } from '../models/entities/registration-tickets'; import { RegistrationTicket } from '@/models/entities/registration-tickets';
import { MessagingMessage } from '../models/entities/messaging-message'; import { MessagingMessage } from '@/models/entities/messaging-message';
import { Signin } from '../models/entities/signin'; import { Signin } from '@/models/entities/signin';
import { AuthSession } from '../models/entities/auth-session'; import { AuthSession } from '@/models/entities/auth-session';
import { FollowRequest } from '../models/entities/follow-request'; import { FollowRequest } from '@/models/entities/follow-request';
import { Emoji } from '../models/entities/emoji'; import { Emoji } from '@/models/entities/emoji';
import { ReversiGame } from '../models/entities/games/reversi/game'; import { ReversiGame } from '@/models/entities/games/reversi/game';
import { ReversiMatching } from '../models/entities/games/reversi/matching'; import { ReversiMatching } from '@/models/entities/games/reversi/matching';
import { UserNotePining } from '../models/entities/user-note-pining'; import { UserNotePining } from '@/models/entities/user-note-pining';
import { Poll } from '../models/entities/poll'; import { Poll } from '@/models/entities/poll';
import { UserKeypair } from '../models/entities/user-keypair'; import { UserKeypair } from '@/models/entities/user-keypair';
import { UserPublickey } from '../models/entities/user-publickey'; import { UserPublickey } from '@/models/entities/user-publickey';
import { UserProfile } from '../models/entities/user-profile'; import { UserProfile } from '@/models/entities/user-profile';
import { UserSecurityKey } from '../models/entities/user-security-key'; import { UserSecurityKey } from '@/models/entities/user-security-key';
import { AttestationChallenge } from '../models/entities/attestation-challenge'; import { AttestationChallenge } from '@/models/entities/attestation-challenge';
import { Page } from '../models/entities/page'; import { Page } from '@/models/entities/page';
import { PageLike } from '../models/entities/page-like'; import { PageLike } from '@/models/entities/page-like';
import { GalleryPost } from '../models/entities/gallery-post'; import { GalleryPost } from '@/models/entities/gallery-post';
import { GalleryLike } from '../models/entities/gallery-like'; import { GalleryLike } from '@/models/entities/gallery-like';
import { ModerationLog } from '../models/entities/moderation-log'; import { ModerationLog } from '@/models/entities/moderation-log';
import { UsedUsername } from '../models/entities/used-username'; import { UsedUsername } from '@/models/entities/used-username';
import { Announcement } from '../models/entities/announcement'; import { Announcement } from '@/models/entities/announcement';
import { AnnouncementRead } from '../models/entities/announcement-read'; import { AnnouncementRead } from '@/models/entities/announcement-read';
import { Clip } from '../models/entities/clip'; import { Clip } from '@/models/entities/clip';
import { ClipNote } from '../models/entities/clip-note'; import { ClipNote } from '@/models/entities/clip-note';
import { Antenna } from '../models/entities/antenna'; import { Antenna } from '@/models/entities/antenna';
import { AntennaNote } from '../models/entities/antenna-note'; import { AntennaNote } from '@/models/entities/antenna-note';
import { PromoNote } from '../models/entities/promo-note'; import { PromoNote } from '@/models/entities/promo-note';
import { PromoRead } from '../models/entities/promo-read'; import { PromoRead } from '@/models/entities/promo-read';
import { program } from '../argv'; import { program } from '../argv';
import { Relay } from '../models/entities/relay'; import { Relay } from '@/models/entities/relay';
import { MutedNote } from '../models/entities/muted-note'; import { MutedNote } from '@/models/entities/muted-note';
import { Channel } from '../models/entities/channel'; import { Channel } from '@/models/entities/channel';
import { ChannelFollowing } from '../models/entities/channel-following'; import { ChannelFollowing } from '@/models/entities/channel-following';
import { ChannelNotePining } from '../models/entities/channel-note-pining'; import { ChannelNotePining } from '@/models/entities/channel-note-pining';
import { RegistryItem } from '../models/entities/registry-item'; import { RegistryItem } from '@/models/entities/registry-item';
import { Ad } from '../models/entities/ad'; import { Ad } from '@/models/entities/ad';
import { PasswordResetRequest } from '@/models/entities/password-reset-request'; import { PasswordResetRequest } from '@/models/entities/password-reset-request';
const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); const sqlLogger = dbLogger.createSubLogger('sql', 'white', false);
@ -211,3 +211,13 @@ export function initDb(justBorrow = false, sync = false, forceRecreate = false)
entities: entities entities: entities
}); });
} }
export async function resetDb() {
const conn = await getConnection();
const tables = await conn.query(`SELECT relname AS "table"
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind = 'r'
AND nspname !~ '^pg_toast';`);
await Promise.all(tables.map(t => t.table).map(x => conn.query(`DELETE FROM "${x}" CASCADE`)));
}

View file

@ -1,5 +1,5 @@
import * as redis from 'redis'; import * as redis from 'redis';
import config from '@/config'; import config from '@/config/index';
export function createConnection() { export function createConnection() {
return redis.createClient( return redis.createClient(

View file

@ -1,11 +1,14 @@
# よくある質問 # よくある質問
ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。 ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。
### iOS/Androidのアプリはありますか ## iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。
ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。 ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。
## Mastodonクライアントでログインできないのですが
MisskeyはMastodonのAPIと互換性がないため、一部を除きMastodonクライアントでMisskeyを利用することはできません。
## 他のサーバーのユーザーをフォローするときは? ## 他のサーバーのユーザーをフォローするときは?
メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io` メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io`

View file

@ -1,7 +1,7 @@
# 用語集 # 用語集
Misskeyに関する用語集です。 Misskeyに関する用語集です。
## AcitivityPub ## ActivityPub
(読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。 (読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。
## AiScript ## AiScript

View file

@ -3,7 +3,7 @@
Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。 Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。
## 歴史 ## 歴史
開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にAcitivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。 開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にActivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。
<div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div> <div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div>
誰でも開発に参加することができ、現在でも活発に開発が続いています。 誰でも開発に参加することができ、現在でも活発に開発が続いています。
@ -72,7 +72,7 @@ Misskeyは開発が進むにつれ使用する技術も大きく変わってき
また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。 また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。
### Mastodonのフォークですか ### Mastodonのフォークですか
いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じAcitivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。 いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じActivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。
### iOS/Androidのアプリはありますか ### iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。

View file

@ -1,11 +1,14 @@
# よくある質問 # よくある質問
ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。 ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。
### iOS/Androidのアプリはありますか ## iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。
ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。 ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。
## Mastodonクライアントでログインできないのですが
MisskeyはMastodonのAPIと互換性がないため、一部を除きMastodonクライアントでMisskeyを利用することはできません。
## 他のサーバーのユーザーをフォローするときは? ## 他のサーバーのユーザーをフォローするときは?
メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io` メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io`

View file

@ -1,7 +1,7 @@
# 用語集 # 用語集
Misskeyに関する用語集です。 Misskeyに関する用語集です。
## AcitivityPub ## ActivityPub
(読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。 (読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。
## AiScript ## AiScript

View file

@ -3,7 +3,7 @@
Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。 Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。
## 歴史 ## 歴史
開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にAcitivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。 開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にActivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。
<div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div> <div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div>
誰でも開発に参加することができ、現在でも活発に開発が続いています。 誰でも開発に参加することができ、現在でも活発に開発が続いています。
@ -72,7 +72,7 @@ Misskeyは開発が進むにつれ使用する技術も大きく変わってき
また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。 また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。
### Mastodonのフォークですか ### Mastodonのフォークですか
いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じAcitivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。 いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じActivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。
### iOS/Androidのアプリはありますか ### iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。

View file

@ -1,11 +1,14 @@
# よくある質問 # よくある質問
ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。 ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。
### iOS/Androidのアプリはありますか ## iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。
ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。 ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。
## Mastodonクライアントでログインできないのですが
MisskeyはMastodonのAPIと互換性がないため、一部を除きMastodonクライアントでMisskeyを利用することはできません。
## 他のサーバーのユーザーをフォローするときは? ## 他のサーバーのユーザーをフォローするときは?
メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io` メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io`

View file

@ -1,7 +1,7 @@
# 用語集 # 用語集
Misskeyに関する用語集です。 Misskeyに関する用語集です。
## AcitivityPub ## ActivityPub
(読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。 (読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。
## AiScript ## AiScript

View file

@ -3,7 +3,7 @@
Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。 Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。
## 歴史 ## 歴史
開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にAcitivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。 開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にActivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。
<div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div> <div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div>
誰でも開発に参加することができ、現在でも活発に開発が続いています。 誰でも開発に参加することができ、現在でも活発に開発が続いています。
@ -72,7 +72,7 @@ Misskeyは開発が進むにつれ使用する技術も大きく変わってき
また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。 また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。
### Mastodonのフォークですか ### Mastodonのフォークですか
いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じAcitivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。 いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じActivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。
### iOS/Androidのアプリはありますか ### iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。

View file

@ -1,8 +1,8 @@
# LTL/STL/GTLの無効化 # Lokale/soziale/globale Chronik deaktivieren
Misskeyでは、LTL/STL/GTLをそれぞれ無効化することができます。有効/無効を切り替えるには、インスタンスコントロールパネルで設定します。 Misskey erlaubt es, die lokale, soziale und globale Chronik jeweils zu deaktivieren. Die Chroniken können in den Instanzeinstellungen aktiviert bzw. deaktiviert werden.
LTLやSTLは、そのインスタンス全員の投稿が見れるため、新規のユーザーにとってはユーザーを探す必要がなくなり、興味のあるユーザーを見つけやすいという利点があります。 しかし同時に、フォロー機能が活用されなくなったり、不適切な投稿が目につきやすくなったり、チャットのようになることで内輪感が生じて逆に新規ユーザーが参加しにくくなるといったデメリットも持ち合わせています。 サーバーによってメリット/デメリットどちらが優勢かは異なるので、オプションとして無効にできるようになっています。 もしデメリットの方が上回っていると感じたら、それらのタイムラインを無効化することも検討してください。 Dass alle Notizen auf deiner Instanz auf der lokalen und sozialen Chronik erscheinen, erleichtert es neuen Nutzern, andere zu finden, ohne dafür die Suche benutzen zu müssen. Es bedeutet jedoch auch, dass es nicht unbedingt nötig ist, Nutzern zu folgen, um ihre Posts zu sehen, und dass häufiger unangebrachte Inhalte zu sehen sein könnten. Die Nutzung gleicht zudem eher der eines Chatrooms, was es neuen Nutzern wiederum erschweren könnte, in Gespräche unter Langzeitnutzern einzusteigen. Diese Vor- und Nachteile wiegen je nach Instanz unterschiedlich schwer, weshalb die Wahl letztendlich den Betreibern überlassen ist. Falls die Nachteile also in deinem Fall überwiegen, kannst du die jeweiligen Chroniken auch deaktivieren.
<div class="warn">⚠️ 無効化を行うと、ユーザーが困惑し、短期的に見て利用者が減る可能性があります。そのため、無効化の際は影響を慎重に検討し、事前に説明してフォローを整える期間を一定程度設けることを推奨します。</div> <div class="warn">⚠️ Das Deaktiveren von Chroniken kann Nutzer verwirren und kurzzeitig abschrecken. Daher solltest du diese Entscheidung gut begründen können und die Nutzer deiner Instanz im Vorfeld darüber aufklären, damit diese sich entsprechend vorbereiten können, beispielsweise indem sie Nutzern folgen, mit denen sie sich häufiger unterhalten.</div>
なお、管理者/モデレーターは、これらのタイムラインの無効化状態は適用されず、引き続き利用することが可能です。 Beachte, dass Aministratoren und Moderatoren diese Chroniken weiterhin sehen können, auch nachdem sie deaktiviert wurden.

View file

@ -1,5 +1,5 @@
# よくある質問 # Häufig gestellte Fragen
ここでは、サーバー管理者向けのよくある質問を掲載しています。 Dieses Dokument richtet sich an Administratoren und beantwortet besonders häufig gestellte Fragen.
## デフォルトテーマを設定したい ## Wie kann ich ein standardmäßiges Farbschema für meine Instanz festlegen?
現在、デフォルトテーマ設定機能は実装されていません。 Derzeit ist es noch nicht möglich, ein standardmäßiges Farbschema für eine Instanz festzulegen.

View file

@ -1,11 +1,14 @@
# よくある質問 # Häufig gestellte Fragen
ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。 ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。
### iOS/Androidのアプリはありますか ## iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。
ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。 ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。
## Mastodonクライアントでログインできないのですが
MisskeyはMastodonのAPIと互換性がないため、一部を除きMastodonクライアントでMisskeyを利用することはできません。
## 他のサーバーのユーザーをフォローするときは? ## 他のサーバーのユーザーをフォローするときは?
メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io` メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io`

View file

@ -1,7 +1,7 @@
# 用語集 # 用語集
Misskeyに関する用語集です。 Misskeyに関する用語集です。
## AcitivityPub ## ActivityPub
(読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。 (読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。
## AiScript ## AiScript

View file

@ -3,7 +3,7 @@
Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。 Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。
## 歴史 ## 歴史
開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にAcitivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。 開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にActivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。
<div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div> <div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div>
誰でも開発に参加することができ、現在でも活発に開発が続いています。 誰でも開発に参加することができ、現在でも活発に開発が続いています。
@ -43,7 +43,7 @@ Misskeyはビジネスではなく、利用は無料であるため、収益は
## クレジット ## クレジット
Misskeyの開発者や、Misskeyに寄付をしてくださった方の一覧は[こちら](/about-misskey)で見ることができます。 Misskeyの開発者や、Misskeyに寄付をしてくださった方の一覧は[こちら](/about-misskey)で見ることができます。
## よくある質問 ## Häufig gestellte Fragen
### プロジェクトは何を目指していますか? ### プロジェクトは何を目指していますか?
強いて言うと、漠然的になりますが広く使われる汎用的なプラットフォームになることを目指しています。 Misskeyは他のプロジェクトとは違い、何らかの思想(例えば、反中央集権)やビジョンに基づいて開発が行われているわけではなく、その点ではフラットです。 それが逆に、特定の方向性に縛られないフレキシブルさを生み出すことに繋がっていると感じています。 強いて言うと、漠然的になりますが広く使われる汎用的なプラットフォームになることを目指しています。 Misskeyは他のプロジェクトとは違い、何らかの思想(例えば、反中央集権)やビジョンに基づいて開発が行われているわけではなく、その点ではフラットです。 それが逆に、特定の方向性に縛られないフレキシブルさを生み出すことに繋がっていると感じています。
<!-- TODO: ここにロードマップへのリンク --> <!-- TODO: ここにロードマップへのリンク -->
@ -72,7 +72,7 @@ Misskeyは開発が進むにつれ使用する技術も大きく変わってき
また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。 また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。
### Mastodonのフォークですか ### Mastodonのフォークですか
いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じAcitivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。 いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じActivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。
### iOS/Androidのアプリはありますか ### iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。

View file

@ -51,4 +51,4 @@ If you enable this option, your note won't be federated to remote instances.
By pinning a note to your profile it will be constantly displayed on your profile page. To pin a note, open the note menu and press "Pin to profile". It's also possible to pin multiple notes to your profile. By pinning a note to your profile it will be constantly displayed on your profile page. To pin a note, open the note menu and press "Pin to profile". It's also possible to pin multiple notes to your profile.
## Watch ## Watch
ノートをウォッチすると、自分以外のノートへのリアクションや返信などの通知を受け取ることができます。 ノートのメニューを開き、「ウォッチ」を選択してウォッチできます。 You can get notifications for replies, reactions etc. for a note that is not yours by watching it. To watch a note, select "Watch" from the respective note's menu.

View file

@ -1,22 +1,25 @@
# Frequently Asked Questions # Frequently Asked Questions
This document will list answers to frequently asked questions regarding the usage of Misskey. Answers to frequently asked questions related to Misskey as a project can be found [here](./misskey). This document will list answers to frequently asked questions regarding the usage of Misskey. Answers to frequently asked questions related to Misskey as a project can be found [here](./misskey).
### "Are there any apps for iOS / Android available?" ## "Are there any apps for iOS / Android available?"
While no official Misskey app for either OS exists, there are several third-party applications. For details, please check [here](./apps). While no official Misskey app for either OS exists, there are several third-party applications. For details, please check [here](./apps).
However, functionality of third-party applications will inevitably lag behind the official Web client, so unless you really want to use a native application, we recommend the official Web client instead. As the Misskey Web client supports PWA, it is possible to make it act as if it was a native application instead. For details regarding this, please check [here](todo). However, functionality of third-party applications will inevitably lag behind the official Web client, so unless you really want to use a native application, we recommend the official Web client instead. As the Misskey Web client supports PWA, it is also possible to make it act as if it was a native application instead. For details regarding this, please check [here](todo).
## "Can't I log in through a Mastodon client?"
As Misskey is not compatible with the Mastodon API, barring some exceptions, using Mastodon clients to log into Misskey is not possible.
## "What do I do when I want to follow users from other servers?" ## "What do I do when I want to follow users from other servers?"
Select the search bar from the menu and enter their username including their host.E.g. `@syuilo@misskey.io` Select the search bar from the menu and enter their username including their host server. E.g.: `@syuilo@misskey.io`
## "How do I take back a Renote?" ## "How do I take back a Renote?"
Press the three dots ("...") to the right of the renote timestamp and select "Take back Renote". To read more about Renotes, please check [here](../features/note). Press the three dots ("...") displayed next to the renote timestamp and select "Take back Renote". To read more about Renotes, please check [here](../features/note).
## "I don't want the preview of an URL to be displayed." ## "I don't want the preview of an URL to be displayed."
You can disable an URL from being previewed using MFM.For details, please check the [MFM Cheatsheet](/mfm-cheat-sheet). You can prevent an URL from being previewed using MFM. Please check the [MFM Cheatsheet](/mfm-cheat-sheet) for more details.
## "I want to add custom emoji." ## "I want to add custom emoji."
Only administrators can add, edit or delete custom emoji.If you'd like to do either of these things, please ask your instance administrator. Only administrators can add, edit or delete custom emoji. If you'd like to do either of these things, please ask your instance administrator.
## "I want to develop a Bot." ## "I want to develop a Bot."
Anyone can develop a Misskey bot using the Misskey API.Please see [here](../advanced/develop-bot). It is possible to develop a Bot using the Misskey API. Please, [see here](../advanced/develop-bot).

View file

@ -1,8 +1,8 @@
# A collection of links # A collection of links
## Websites ## Websites
- [Official Discord](https://discord.gg/Wp8gVStHW3) - The official Discord server for Misskey
- [Misskey Forum](https://forum.misskey.io/) - A forum used for questions surrounding Misskey - [Misskey Forum](https://forum.misskey.io/) - A forum used for questions surrounding Misskey
- [Misskey Forum](https://forum.misskey.io/) - Misskeyに関する話題を扱うフォーラム
## Accounts ## Accounts
- [@repo@misskey.io](https://misskey.io/@repo) - A bot that publishes posts about updates to the Misskey repository - [@repo@misskey.io](https://misskey.io/@repo) - A bot that publishes posts about updates to the Misskey repository

View file

@ -1,4 +1,4 @@
# LTL/STL/GTLの無効化 # Malebligo de loka/sociala/malloka templinio
Misskeyでは、LTL/STL/GTLをそれぞれ無効化することができます。有効/無効を切り替えるには、インスタンスコントロールパネルで設定します。 Misskeyでは、LTL/STL/GTLをそれぞれ無効化することができます。有効/無効を切り替えるには、インスタンスコントロールパネルで設定します。
LTLやSTLは、そのインスタンス全員の投稿が見れるため、新規のユーザーにとってはユーザーを探す必要がなくなり、興味のあるユーザーを見つけやすいという利点があります。 しかし同時に、フォロー機能が活用されなくなったり、不適切な投稿が目につきやすくなったり、チャットのようになることで内輪感が生じて逆に新規ユーザーが参加しにくくなるといったデメリットも持ち合わせています。 サーバーによってメリット/デメリットどちらが優勢かは異なるので、オプションとして無効にできるようになっています。 もしデメリットの方が上回っていると感じたら、それらのタイムラインを無効化することも検討してください。 LTLやSTLは、そのインスタンス全員の投稿が見れるため、新規のユーザーにとってはユーザーを探す必要がなくなり、興味のあるユーザーを見つけやすいという利点があります。 しかし同時に、フォロー機能が活用されなくなったり、不適切な投稿が目につきやすくなったり、チャットのようになることで内輪感が生じて逆に新規ユーザーが参加しにくくなるといったデメリットも持ち合わせています。 サーバーによってメリット/デメリットどちらが優勢かは異なるので、オプションとして無効にできるようになっています。 もしデメリットの方が上回っていると感じたら、それらのタイムラインを無効化することも検討してください。

View file

@ -32,7 +32,7 @@ UUIDを生成する。以後これをセッションIDと呼びます。
表示する際、URLにクエリパラメータとしていくつかのオプションを設定できます: 表示する際、URLにクエリパラメータとしていくつかのオプションを設定できます:
* `name` ... アプリケーション名 * `name` ... アプリケーション名
* > 例: `MissDeck` * > 例: `MissDeck`
* `icon` ... アプリケーションのアイコン画像URL * `icon` ... URL de ikono de la programo
* > 例: `https://missdeck.example.com/icon.png` * > 例: `https://missdeck.example.com/icon.png`
* `callback` ... 認証が終わった後にリダイレクトするURL * `callback` ... 認証が終わった後にリダイレクトするURL
* > 例: `https://missdeck.example.com/callback` * > 例: `https://missdeck.example.com/callback`
@ -51,7 +51,7 @@ UUIDを生成する。以後これをセッションIDと呼びます。
[「APIの使い方」へ進む](#APIの使い方) [「APIの使い方」へ進む](#APIの使い方)
## APIの使い方 ## Uzado de API
**APIはすべてPOSTで、リクエスト/レスポンスともにJSON形式です。RESTではありません。** アクセストークンは、`i`というパラメータ名でリクエストに含めます。 **APIはすべてPOSTで、リクエスト/レスポンスともにJSON形式です。RESTではありません。** アクセストークンは、`i`というパラメータ名でリクエストに含めます。
* [APIリファレンス](/api-doc) * [APIリファレンス](/api-doc)

View file

@ -1,4 +1,4 @@
# アンテナ # Antenoj
アンテナは、自由に条件を設定して、合致するノートを自動で収集することができる機能です。 アンテナは、自由に条件を設定して、合致するノートを自動で収集することができる機能です。
条件を設定したアンテナが作成された状態で、条件に合致するノートが投稿されると、リアルタイムでそのアンテナのタイムラインにノートが追加されます。 条件を設定したアンテナが作成された状態で、条件に合致するノートが投稿されると、リアルタイムでそのアンテナのタイムラインにノートが追加されます。

View file

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

View file

@ -1,4 +1,4 @@
# Diskingo # Disko
ドライブは、Misskey上でファイルを管理できる機能です。 ドライブは、Misskey上でファイルを管理できる機能です。
[ドライブのページ](/my/drive)から任意のファイルをアップロードできるほか、アバターに設定した画像や、ノートに添付したファイルなどもすべてドライブにアップロードされます。 [ドライブのページ](/my/drive)から任意のファイルをアップロードできるほか、アバターに設定した画像や、ノートに添付したファイルなどもすべてドライブにアップロードされます。

View file

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

View file

@ -51,4 +51,4 @@ Contents Warningの略で、ートの内容を、閲覧者の操作なしに
ノートをピン留めすると、ユーザーページに常にそのノートを表示しておくことができます。 ノートのメニューを開き、「ピン留め」を選択してピン留めできます。 複数のノートをピン留めできます。 ノートをピン留めすると、ユーザーページに常にそのノートを表示しておくことができます。 ノートのメニューを開き、「ピン留め」を選択してピン留めできます。 複数のノートをピン留めできます。
## Observi ## Observi
ノートをウォッチすると、自分以外のノートへのリアクションや返信などの通知を受け取ることができます。 ノートのメニューを開き、「ウォッチ」を選択してウォッチできます。 Vi povas ricevi sciigojn pri reagoj, respondoj, ktp al noto, kiuj ne apartenas al vi. Por observu, malfermu respektivan menuon de noto, kaj elektu la "Observi" el ĝi.

View file

@ -10,22 +10,22 @@
## Sociala ## Sociala
自分のフォローしているユーザーの投稿と、全てのローカルユーザーの「ホーム」指定されていない投稿が流れます。STLと略されます。 自分のフォローしているユーザーの投稿と、全てのローカルユーザーの「ホーム」指定されていない投稿が流れます。STLと略されます。
## Konfederacia ## Malloka
全てのローカルユーザーの「ホーム」指定されていない投稿と、サーバーに届いた全てのリモートユーザーの「ホーム」指定されていない投稿が流れます。GTLと略されます。 全てのローカルユーザーの「ホーム」指定されていない投稿と、サーバーに届いた全てのリモートユーザーの「ホーム」指定されていない投稿が流れます。GTLと略されます。
## 比較 ## 比較
| ソース | | | Templinio | | | | ソース | | | Templinio | | |
| ------------ | --------- | ----- | --------- | ------- | ------------ | | ------------ | --------- | ----- | --------- | ------- | ------- |
| Uzanto | 公開範囲 | Hejmo | Loka | Sociala | Konfederacia | | Uzanto | 公開範囲 | Hejmo | Loka | Sociala | Malloka |
| ローカル (フォロー) | Publikigi | ✔ | ✔ | ✔ | ✔ | | ローカル (フォロー) | Publikigi | ✔ | ✔ | ✔ | ✔ |
| | Hejmo | ✔ | | ✔ | | | | Hejmo | ✔ | | ✔ | |
| | Sekvantoj | ✔ | ✔ | ✔ | ✔ | | | Sekvantoj | ✔ | ✔ | ✔ | ✔ |
| リモート (フォロー) | Publikigi | ✔ | | ✔ | ✔ | | リモート (フォロー) | Publikigi | ✔ | | ✔ | ✔ |
| | Hejmo | ✔ | | ✔ | | | | Hejmo | ✔ | | ✔ | |
| | Sekvantoj | ✔ | | ✔ | ✔ | | | Sekvantoj | ✔ | | ✔ | ✔ |
| ローカル (未フォロー) | Publikigi | | ✔ | ✔ | ✔ | | ローカル (未フォロー) | Publikigi | | ✔ | ✔ | ✔ |
| | Hejmo | | | | | | | Hejmo | | | | |
| | Sekvantoj | | | | | | | Sekvantoj | | | | |
| リモート (未フォロー) | Publikigi | | | | ✔ | | リモート (未フォロー) | Publikigi | | | | ✔ |
| | Hejmo | | | | | | | Hejmo | | | | |
| | Sekvantoj | | | | | | | Sekvantoj | | | | |

View file

@ -1,5 +1,5 @@
# サードパーティアプリのリスト # サードパーティアプリのリスト
## クライアント ## Klientoj
todo todo
## 連携サービス ## 連携サービス

View file

@ -1,11 +1,14 @@
# よくある質問 # よくある質問
ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。 ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。
### iOS/Androidのアプリはありますか ## iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。 公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。
ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。 ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。
## Mastodonクライアントでログインできないのですが
MisskeyはMastodonのAPIと互換性がないため、一部を除きMastodonクライアントでMisskeyを利用することはできません。
## 他のサーバーのユーザーをフォローするときは? ## 他のサーバーのユーザーをフォローするときは?
メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io` メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io`

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