Firefish v1.0
This commit is contained in:
commit
fe91a9fd47
2279 changed files with 314731 additions and 0 deletions
13
.config/LICENSE
Normal file
13
.config/LICENSE
Normal file
|
@ -0,0 +1,13 @@
|
|||
Copyright 2023 Firefish
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
195
.config/ci.yml
Normal file
195
.config/ci.yml
Normal file
|
@ -0,0 +1,195 @@
|
|||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# Firefish configuration
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
# ┌─────┐
|
||||
#───┘ URL └─────────────────────────────────────────────────────
|
||||
|
||||
# Final accessible URL seen by a user.
|
||||
url: https://example.tld/
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# URL SETTINGS AFTER THAT!
|
||||
|
||||
# ┌───────────────────────┐
|
||||
#───┘ Port and TLS settings └───────────────────────────────────
|
||||
|
||||
#
|
||||
# Misskey requires a reverse proxy to support HTTPS connections.
|
||||
#
|
||||
# +----- https://example.tld/ ------------+
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# | User | ---> || Proxy (443) | ---> | Misskey (3000) ||
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# +---------------------------------------+
|
||||
#
|
||||
# You need to set up a reverse proxy. (e.g. nginx)
|
||||
# An encrypted connection with HTTPS is highly recommended
|
||||
# because tokens may be transferred in GET requests.
|
||||
|
||||
# The port that your Misskey server should listen on.
|
||||
port: 3000
|
||||
|
||||
# ┌──────────────────────────┐
|
||||
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||
|
||||
db:
|
||||
host: database
|
||||
port: 5432
|
||||
|
||||
# Database name
|
||||
db: postgres
|
||||
|
||||
# Auth
|
||||
user: postgres
|
||||
pass: test
|
||||
|
||||
# Whether disable Caching queries
|
||||
#disableCache: true
|
||||
|
||||
# Extra Connection options
|
||||
#extra:
|
||||
# ssl: true
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Redis configuration └─────────────────────────────────────
|
||||
|
||||
redis:
|
||||
host: redis
|
||||
port: 6379
|
||||
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||
#pass: example-pass
|
||||
#prefix: example-prefix
|
||||
#db: 1
|
||||
|
||||
# ┌─────────────────────────────┐
|
||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||
|
||||
#elasticsearch:
|
||||
# host: localhost
|
||||
# port: 9200
|
||||
# ssl: false
|
||||
# user:
|
||||
# pass:
|
||||
|
||||
# ┌───────────────┐
|
||||
#───┘ ID generation └───────────────────────────────────────────
|
||||
|
||||
# You can select the ID generation method.
|
||||
# You don't usually need to change this setting, but you can
|
||||
# change it according to your preferences.
|
||||
|
||||
# Available methods:
|
||||
# aid ... Short, Millisecond accuracy
|
||||
# meid ... Similar to ObjectID, Millisecond accuracy
|
||||
# ulid ... Millisecond accuracy
|
||||
# objectid ... This is left for backward compatibility
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# ID SETTINGS AFTER THAT!
|
||||
|
||||
id: 'aid'
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Other configuration └─────────────────────────────────────
|
||||
|
||||
# Max note length, should be < 8000.
|
||||
#maxNoteLength: 3000
|
||||
|
||||
# Whether disable HSTS
|
||||
#disableHsts: true
|
||||
|
||||
# Number of worker processes
|
||||
#clusterLimit: 1
|
||||
|
||||
# Job concurrency per worker
|
||||
# deliverJobConcurrency: 128
|
||||
# inboxJobConcurrency: 16
|
||||
|
||||
# Job rate limiter
|
||||
# deliverJobPerSec: 128
|
||||
# inboxJobPerSec: 16
|
||||
|
||||
# Job attempts
|
||||
# deliverJobMaxAttempts: 12
|
||||
# inboxJobMaxAttempts: 8
|
||||
|
||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||
#outgoingAddressFamily: ipv4
|
||||
|
||||
# Syslog option
|
||||
#syslog:
|
||||
# host: localhost
|
||||
# port: 514
|
||||
|
||||
# Proxy for HTTP/HTTPS
|
||||
#proxy: http://127.0.0.1:3128
|
||||
|
||||
#proxyBypassHosts: [
|
||||
# 'example.com',
|
||||
# '192.0.2.8'
|
||||
#]
|
||||
|
||||
# Proxy for SMTP/SMTPS
|
||||
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
|
||||
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
|
||||
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
|
||||
|
||||
# Media Proxy
|
||||
#mediaProxy: https://example.com/proxy
|
||||
|
||||
# Proxy remote files (default: false)
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
#allowedPrivateNetworks: [
|
||||
# '127.0.0.1/32'
|
||||
#]
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
||||
|
||||
# Managed hosting settings
|
||||
# !!!!!!!!!!
|
||||
# >>>>>> NORMAL SELF-HOSTERS, STAY AWAY! <<<<<<
|
||||
# >>>>>> YOU DON'T NEED THIS! <<<<<<
|
||||
# !!!!!!!!!!
|
||||
# Each category is optional, but if each item in each category is mandatory!
|
||||
# If you mess this up, that's on you, you've been warned...
|
||||
|
||||
#maxUserSignups: 100
|
||||
#isManagedHosting: true
|
||||
#deepl:
|
||||
# managed: true
|
||||
# authKey: ''
|
||||
# isPro: false
|
||||
#
|
||||
#email:
|
||||
# managed: true
|
||||
# address: 'example@email.com'
|
||||
# host: 'email.com'
|
||||
# port: 587
|
||||
# user: 'example@email.com'
|
||||
# pass: ''
|
||||
# useImplicitSslTls: false
|
||||
#
|
||||
#objectStorage:
|
||||
# managed: true
|
||||
# baseUrl: ''
|
||||
# bucket: ''
|
||||
# prefix: ''
|
||||
# endpoint: ''
|
||||
# region: ''
|
||||
# accessKey: ''
|
||||
# secretKey: ''
|
||||
# useSsl: true
|
||||
# connnectOverProxy: false
|
||||
# setPublicReadOnUpload: true
|
||||
# s3ForcePathStyle: true
|
||||
|
||||
# !!!!!!!!!!
|
||||
# >>>>>> AGAIN, NORMAL SELF-HOSTERS, STAY AWAY! <<<<<<
|
||||
# >>>>>> YOU DON'T NEED THIS, ABOVE SETTINGS ARE FOR MANAGED HOSTING ONLY! <<<<<<
|
||||
# !!!!!!!!!!
|
||||
|
||||
# Seriously. Do NOT fill out the above settings if you're self-hosting.
|
||||
# They're much better off being set from the control panel.
|
38
.config/devenv.yml
Normal file
38
.config/devenv.yml
Normal file
|
@ -0,0 +1,38 @@
|
|||
url: http://localhost:3000
|
||||
port: 3000
|
||||
|
||||
db:
|
||||
host: 127.0.0.1
|
||||
port: 5432
|
||||
|
||||
db: firefish
|
||||
|
||||
user: firefish
|
||||
pass: firefish
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
family: 4
|
||||
#sonic:
|
||||
# host: localhost
|
||||
# port: 1491
|
||||
# auth: SecretPassword
|
||||
# collection: notes
|
||||
# bucket: default
|
||||
|
||||
#elasticsearch:
|
||||
# host: localhost
|
||||
# port: 9200
|
||||
# ssl: false
|
||||
# user:
|
||||
# pass:
|
||||
|
||||
id: 'aid'
|
||||
|
||||
reservedUsernames:
|
||||
- root
|
||||
- admin
|
||||
- administrator
|
||||
- me
|
||||
- system
|
4
.config/docker_example.env
Normal file
4
.config/docker_example.env
Normal file
|
@ -0,0 +1,4 @@
|
|||
# db settings
|
||||
POSTGRES_PASSWORD=example-firefish-pass
|
||||
POSTGRES_USER=example-firefish-user
|
||||
POSTGRES_DB=firefish
|
253
.config/example.yml
Normal file
253
.config/example.yml
Normal file
|
@ -0,0 +1,253 @@
|
|||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# Firefish configuration
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
# After starting your server, please don't change the URL! Doing so will break federation.
|
||||
|
||||
# ┌─────┐
|
||||
#───┘ URL └─────────────────────────────────────────────────────
|
||||
|
||||
# Final accessible URL seen by a user.
|
||||
url: https://example.com/
|
||||
|
||||
# ┌───────────────────────┐
|
||||
#───┘ Port and TLS settings └───────────────────────────────────
|
||||
|
||||
#
|
||||
# Firefish requires a reverse proxy to support HTTPS connections.
|
||||
#
|
||||
# +----- https://example.com/ ------------+
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# | User | ---> || Proxy (443) | ---> | Firefish (3000) ||
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# +---------------------------------------+
|
||||
#
|
||||
# You need to set up a reverse proxy. (e.g. nginx, caddy)
|
||||
# An encrypted connection with HTTPS is highly recommended
|
||||
# because tokens may be transferred in GET requests.
|
||||
|
||||
# The port that your Firefish server should listen on.
|
||||
port: 3000
|
||||
|
||||
# ┌──────────────────────────┐
|
||||
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||
|
||||
db:
|
||||
host: localhost
|
||||
port: 5432
|
||||
#ssl: false
|
||||
# Database name
|
||||
db: firefish
|
||||
|
||||
# Auth
|
||||
user: example-firefish-user
|
||||
pass: example-firefish-pass
|
||||
|
||||
# Whether disable Caching queries
|
||||
#disableCache: true
|
||||
|
||||
# Extra Connection options
|
||||
#extra:
|
||||
# ssl:
|
||||
# host: localhost
|
||||
# rejectUnauthorized: false
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Redis configuration └─────────────────────────────────────
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
#tls:
|
||||
# host: localhost
|
||||
# rejectUnauthorized: false
|
||||
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||
#pass: example-pass
|
||||
#prefix: example-prefix
|
||||
#db: 1
|
||||
#user: default
|
||||
|
||||
# ┌─────────────────────────────┐
|
||||
#───┘ Cache server configuration └─────────────────────────────────────
|
||||
|
||||
# A Redis-compatible server (DragonflyDB, Keydb, Redis) for caching
|
||||
# If left blank, it will use the Redis server from above
|
||||
|
||||
#cacheServer:
|
||||
#host: localhost
|
||||
#port: 6379
|
||||
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||
#pass: example-pass
|
||||
#prefix: example-prefix
|
||||
#db: 1
|
||||
|
||||
# Please configure either MeiliSearch *or* Sonic.
|
||||
# If both MeiliSearch and Sonic configurations are present, MeiliSearch will take precedence.
|
||||
|
||||
# ┌───────────────────────────┐
|
||||
#───┘ MeiliSearch configuration └─────────────────────────────────────
|
||||
#meilisearch:
|
||||
# host: meilisearch
|
||||
# port: 7700
|
||||
# ssl: false
|
||||
# apiKey:
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Sonic configuration └─────────────────────────────────────
|
||||
|
||||
#sonic:
|
||||
# host: localhost
|
||||
# port: 1491
|
||||
# auth: SecretPassword
|
||||
# collection: notes
|
||||
# bucket: default
|
||||
|
||||
|
||||
# ┌───────────────┐
|
||||
#───┘ ID generation └───────────────────────────────────────────
|
||||
|
||||
# No need to uncomment in most cases, but you may want to change
|
||||
# these settings if you plan to run a large and/or distributed server.
|
||||
|
||||
# cuid:
|
||||
# # Min 16, Max 24
|
||||
# length: 16
|
||||
#
|
||||
# # Set this to a unique string across workers (e.g., machine's hostname)
|
||||
# # if your workers are running in multiple hosts.
|
||||
# fingerprint: my-fingerprint
|
||||
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Other configuration └─────────────────────────────────────
|
||||
|
||||
# Maximum length of a post (default 3000, max 100000)
|
||||
#maxNoteLength: 3000
|
||||
|
||||
# Maximum length of an image caption (default 1500, max 8192)
|
||||
#maxCaptionLength: 1500
|
||||
|
||||
# Reserved usernames that only the administrator can register with
|
||||
reservedUsernames: [
|
||||
'root',
|
||||
'admin',
|
||||
'administrator',
|
||||
'me',
|
||||
'system'
|
||||
]
|
||||
|
||||
# Whether disable HSTS
|
||||
#disableHsts: true
|
||||
|
||||
# Number of worker processes
|
||||
#clusterLimit: 1
|
||||
|
||||
# Worker only mode
|
||||
#onlyQueueProcessor: 1
|
||||
|
||||
# Job concurrency per worker
|
||||
# deliverJobConcurrency: 128
|
||||
# inboxJobConcurrency: 16
|
||||
|
||||
# Job rate limiter
|
||||
# deliverJobPerSec: 128
|
||||
# inboxJobPerSec: 16
|
||||
|
||||
# Job attempts
|
||||
# deliverJobMaxAttempts: 12
|
||||
# inboxJobMaxAttempts: 8
|
||||
|
||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||
#outgoingAddressFamily: ipv4
|
||||
|
||||
# Syslog option
|
||||
#syslog:
|
||||
# host: localhost
|
||||
# port: 514
|
||||
|
||||
# Proxy for HTTP/HTTPS
|
||||
#proxy: http://127.0.0.1:3128
|
||||
|
||||
#proxyBypassHosts: [
|
||||
# 'web.kaiteki.app',
|
||||
# 'example.com',
|
||||
# '192.0.2.8'
|
||||
#]
|
||||
|
||||
# Proxy for SMTP/SMTPS
|
||||
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
|
||||
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
|
||||
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
|
||||
|
||||
# Media Proxy
|
||||
#mediaProxy: https://example.com/proxy
|
||||
|
||||
# Proxy remote files (default: false)
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
#allowedPrivateNetworks: [
|
||||
# '127.0.0.1/32'
|
||||
#]
|
||||
|
||||
# TWA
|
||||
#twa:
|
||||
# nameSpace: android_app
|
||||
# packageName: tld.domain.twa
|
||||
# sha256CertFingerprints: ['AB:CD:EF']
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
||||
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# Congrats, you've reached the end of the config file needed for most deployments!
|
||||
# Enjoy your Firefish server!
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
|
||||
|
||||
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# Managed hosting settings
|
||||
# >>> NORMAL SELF-HOSTERS, STAY AWAY! <<<
|
||||
# >>> YOU DON'T NEED THIS! <<<
|
||||
# Each category is optional, but if each item in each category is mandatory!
|
||||
# If you mess this up, that's on you, you've been warned...
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
#maxUserSignups: 100
|
||||
#isManagedHosting: true
|
||||
#deepl:
|
||||
# managed: true
|
||||
# authKey: ''
|
||||
# isPro: false
|
||||
#
|
||||
#email:
|
||||
# managed: true
|
||||
# address: 'example@email.com'
|
||||
# host: 'email.com'
|
||||
# port: 587
|
||||
# user: 'example@email.com'
|
||||
# pass: ''
|
||||
# useImplicitSslTls: false
|
||||
#
|
||||
#objectStorage:
|
||||
# managed: true
|
||||
# baseUrl: ''
|
||||
# bucket: ''
|
||||
# prefix: ''
|
||||
# endpoint: ''
|
||||
# region: ''
|
||||
# accessKey: ''
|
||||
# secretKey: ''
|
||||
# useSsl: true
|
||||
# connnectOverProxy: false
|
||||
# setPublicReadOnUpload: true
|
||||
# s3ForcePathStyle: true
|
||||
|
||||
# !!!!!!!!!!
|
||||
# >>>>>> AGAIN, NORMAL SELF-HOSTERS, STAY AWAY! <<<<<<
|
||||
# >>>>>> YOU DON'T NEED THIS, ABOVE SETTINGS ARE FOR MANAGED HOSTING ONLY! <<<<<<
|
||||
# !!!!!!!!!!
|
||||
|
||||
# Seriously. Do NOT fill out the above settings if you're self-hosting.
|
||||
# They're much better off being set from the control panel.
|
82
.config/helm_values_example.yml
Normal file
82
.config/helm_values_example.yml
Normal file
|
@ -0,0 +1,82 @@
|
|||
replicaCount: 1
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 0.5
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 1
|
||||
memory: 1Gi
|
||||
|
||||
firefish:
|
||||
domain: example.tld
|
||||
smtp:
|
||||
from_address: noreply@example.tld
|
||||
port: 587
|
||||
server: smtp.gmail.com
|
||||
useImplicitSslTls: false
|
||||
login: me@example.tld
|
||||
password: CHANGEME
|
||||
objectStorage:
|
||||
baseUrl: https://example-bucket.nyc3.cdn.digitaloceanspaces.com
|
||||
access_key: CHANGEME
|
||||
access_secret: CHANGEME
|
||||
bucket: example-bucket
|
||||
endpoint: nyc3.digitaloceanspaces.com:443
|
||||
region: nyc3
|
||||
allowedPrivateNetworks: []
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
hosts:
|
||||
- host: example.tld
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
tls:
|
||||
- secretName: example-tld-certificate
|
||||
hosts:
|
||||
- example.tld
|
||||
|
||||
elasticsearch:
|
||||
enabled: false
|
||||
|
||||
postgresql:
|
||||
auth:
|
||||
password: CHANGEME
|
||||
postgresPassword: CHANGEME
|
||||
primary:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: vultr-block-storage
|
||||
size: 25Gi
|
||||
resources:
|
||||
requests:
|
||||
cpu: 0.25
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 0.5
|
||||
memory: 512Mi
|
||||
metrics:
|
||||
enabled: true
|
||||
|
||||
redis:
|
||||
auth:
|
||||
password: CHANGEME
|
||||
master:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 0.25
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 0.5
|
||||
memory: 256Mi
|
||||
persistence:
|
||||
storageclass: vultr-block-storage
|
||||
size: 10Gi
|
||||
replica:
|
||||
replicaCount: 0
|
||||
metrics:
|
||||
enabled: true
|
44
.dockerignore
Normal file
44
.dockerignore
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Visual Studio Code
|
||||
.vscode
|
||||
|
||||
# Intelij-IDEA
|
||||
.idea
|
||||
|
||||
# Node.js
|
||||
node_modules
|
||||
**/node_modules
|
||||
report.*.json
|
||||
|
||||
# Rust
|
||||
packages/backend/native-utils/target
|
||||
|
||||
# Cypress
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
|
||||
# Coverage
|
||||
coverage
|
||||
|
||||
# config
|
||||
/.config
|
||||
|
||||
# misskey
|
||||
built
|
||||
db
|
||||
elasticsearch
|
||||
redis
|
||||
npm-debug.log
|
||||
*.pem
|
||||
run.bat
|
||||
api-docs.json
|
||||
*.log
|
||||
*.code-workspace
|
||||
.DS_Store
|
||||
files
|
||||
ormconfig.json
|
||||
packages/backend/assets/instance.css
|
||||
|
||||
# dockerignore custom
|
||||
.git
|
||||
Dockerfile
|
||||
docker-compose.yml
|
10
.editorconfig
Normal file
10
.editorconfig
Normal file
|
@ -0,0 +1,10 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
4
.envrc
Normal file
4
.envrc
Normal file
|
@ -0,0 +1,4 @@
|
|||
if ! has nix_direnv_version || ! nix_direnv_version 2.3.0; then
|
||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc" "sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8="
|
||||
fi
|
||||
use flake . --impure
|
7
.gitattributes
vendored
Normal file
7
.gitattributes
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
*.svg -diff -text
|
||||
*.psd -diff -text
|
||||
*.ai -diff -text
|
||||
*.mqo -diff -text
|
||||
*.glb -diff -text
|
||||
*.blend -diff -text
|
||||
*.afdesign -diff -text
|
74
.gitignore
vendored
Normal file
74
.gitignore
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
# Visual Studio Code
|
||||
/.vscode
|
||||
!/.vscode/extensions.json
|
||||
|
||||
# Intelij-IDEA
|
||||
/.idea
|
||||
packages/backend/.idea/backend.iml
|
||||
packages/backend/.idea/modules.xml
|
||||
packages/backend/.idea/vcs.xml
|
||||
|
||||
# Node.js
|
||||
node_modules
|
||||
report.*.json
|
||||
|
||||
# Cypress
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
|
||||
# Coverage
|
||||
coverage
|
||||
|
||||
# config
|
||||
/.config/*
|
||||
!/.config/example.yml
|
||||
!/.config/devenv.yml
|
||||
!/.config/docker_example.env
|
||||
!/.config/helm_values_example.yml
|
||||
!/.config/LICENSE
|
||||
|
||||
# docker dev config
|
||||
/dev/docker-compose.yml
|
||||
|
||||
# misskey
|
||||
built
|
||||
db
|
||||
elasticsearch
|
||||
redis
|
||||
npm-debug.log
|
||||
*.pem
|
||||
run.bat
|
||||
api-docs.json
|
||||
*.log
|
||||
*.code-workspace
|
||||
.DS_Store
|
||||
files
|
||||
ormconfig.json
|
||||
packages/backend/assets/instance.css
|
||||
packages/backend/assets/sounds/None.mp3
|
||||
packages/backend/assets/LICENSE
|
||||
|
||||
!/packages/backend/queue/processors/db
|
||||
!packages/backend/src/db
|
||||
|
||||
packages/megalodon/lib
|
||||
packages/megalodon/.idea
|
||||
|
||||
# blender backups
|
||||
*.blend1
|
||||
*.blend2
|
||||
*.blend3
|
||||
*.blend4
|
||||
*.blend5
|
||||
|
||||
# old yarn
|
||||
.yarn
|
||||
yarn*
|
||||
|
||||
# Nix Development shell items
|
||||
.devenv
|
||||
.direnv
|
||||
|
||||
# Cargo cache for Docker
|
||||
/.cargo-cache
|
||||
/.cargo-target
|
1
.node-version
Normal file
1
.node-version
Normal file
|
@ -0,0 +1 @@
|
|||
v18.16.0
|
1
.npmrc
Normal file
1
.npmrc
Normal file
|
@ -0,0 +1 @@
|
|||
use-lockfile-v6=true
|
11
.vscode/extensions.json
vendored
Normal file
11
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"editorconfig.editorconfig",
|
||||
"eg2.vscode-npm-script",
|
||||
"rome.rome",
|
||||
"Vue.volar",
|
||||
"Vue.vscode-typescript-vue-plugin",
|
||||
"arcanis.vscode-zipfs",
|
||||
"Orta.vscode-twoslash-queries"
|
||||
]
|
||||
}
|
4
.vsls.json
Normal file
4
.vsls.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/vsls",
|
||||
"gitignore": "exclude"
|
||||
}
|
3
.weblate
Normal file
3
.weblate
Normal file
|
@ -0,0 +1,3 @@
|
|||
[weblate]
|
||||
url = https://hosted.weblate.org/api/
|
||||
translation = firefish/locales
|
22
.woodpecker/commit.yml
Normal file
22
.woodpecker/commit.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
pipeline:
|
||||
testCommit:
|
||||
image: node:alpine
|
||||
commands:
|
||||
- apk add --no-cache cargo python3 make g++
|
||||
- cp .config/ci.yml .config/default.yml
|
||||
- corepack enable
|
||||
- corepack prepare pnpm@latest --activate
|
||||
- pnpm i --frozen-lockfile
|
||||
- pnpm run build
|
||||
- pnpm run migrate
|
||||
|
||||
services:
|
||||
database:
|
||||
image: postgres:15
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=test
|
||||
redis:
|
||||
image: redis
|
||||
|
||||
branches:
|
||||
include: [ main, beta, develop, feature/* ]
|
15
.woodpecker/dockerHubRelease.yml
Normal file
15
.woodpecker/dockerHubRelease.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
pipeline:
|
||||
publish-docker-latest:
|
||||
image: plugins/kaniko
|
||||
settings:
|
||||
repo: thatonecalculator/firefish
|
||||
tags: latest
|
||||
dockerfile: Dockerfile
|
||||
username:
|
||||
# Secret 'docker_username' needs to be set in the CI settings
|
||||
from_secret: docker_username
|
||||
password:
|
||||
# Secret 'docker_password' needs to be set in the CI settings
|
||||
from_secret: docker_password
|
||||
|
||||
branches: main
|
14
.woodpecker/dockerHubReleaseCandidate.yml
Normal file
14
.woodpecker/dockerHubReleaseCandidate.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
pipeline:
|
||||
publish-docker-latest:
|
||||
image: plugins/kaniko
|
||||
settings:
|
||||
repo: thatonecalculator/firefish
|
||||
tags: rc
|
||||
dockerfile: Dockerfile
|
||||
username:
|
||||
# Secret 'docker_username' needs to be set in the CI settings
|
||||
from_secret: docker_username
|
||||
password:
|
||||
# Secret 'docker_password' needs to be set in the CI settings
|
||||
from_secret: docker_password
|
||||
branches: beta
|
18
.woodpecker/dockerHubTag.yml
Normal file
18
.woodpecker/dockerHubTag.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
pipeline:
|
||||
publish-docker-tag:
|
||||
image: plugins/kaniko
|
||||
settings:
|
||||
repo: thatonecalculator/firefish
|
||||
# Uses the tag from git for the container tag
|
||||
tags: ${CI_COMMIT_TAG}
|
||||
dockerfile: Dockerfile
|
||||
username:
|
||||
# Secret 'docker_username' needs to be set in the CI settings
|
||||
from_secret: docker_username
|
||||
password:
|
||||
# Secret 'docker_password' needs to be set in the CI settings
|
||||
from_secret: docker_password
|
||||
when:
|
||||
# Push new version when version tag is created
|
||||
event: tag
|
||||
tag: v*
|
11
.woodpecker/testDocker.yml
Normal file
11
.woodpecker/testDocker.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
pipeline:
|
||||
docker-build:
|
||||
image: plugins/kaniko
|
||||
settings:
|
||||
repo: thatonecalculator/firefish
|
||||
tags: test
|
||||
dockerfile: Dockerfile
|
||||
no_push: true
|
||||
|
||||
branches:
|
||||
include: [ main, develop, beta ]
|
14981
CHANGELOG.md
Normal file
14981
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load diff
136
CODE_OF_CONDUCT.md
Normal file
136
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,136 @@
|
|||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
@t1c on Prometheus Gitlab,
|
||||
`@kainoa@firefish.social` on the Fediverse,
|
||||
or kainoa@t1c.dev via email.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
276
CONTRIBUTING.md
Normal file
276
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,276 @@
|
|||
# Contribution guide
|
||||
We're glad you're interested in contributing Firefish! In this document you will find the information you need to contribute to the project.
|
||||
|
||||
## Translation (i18n)
|
||||
Firefish uses [Weblate](hhttps://hosted.weblate.org/engage/firefish/) for translation and internationalization management.
|
||||
|
||||
If your language is not listed in Weblate, please open an issue.
|
||||
|
||||
You can contribute without knowing how to code by helping translate here:
|
||||
|
||||
[![Translation status](https://hosted.weblate.org/widgets/firefish/-/287x66-grey.png)](https://hosted.weblate.org/engage/firefish/)
|
||||
|
||||
[![Translation bars](https://hosted.weblate.org/widgets/firefish/-/multi-auto.svg)](https://hosted.weblate.org/engage/firefish/)
|
||||
|
||||
## Roadmap
|
||||
See [FIREFISH.md](./FIREFISH.md)
|
||||
|
||||
## Issues
|
||||
Before creating an issue, please check the following:
|
||||
- To avoid duplication, please search for similar issues before creating a new issue.
|
||||
- Do not use Issues to ask questions or troubleshooting.
|
||||
- Issues should only be used to feature requests, suggestions, and bug tracking.
|
||||
- Please ask questions or troubleshooting in the [Matrix room](https://matrix.to/#/#firefish:matrix.fedibird.com).
|
||||
|
||||
> **Warning**
|
||||
> Do not close issues that are about to be resolved. It should remain open until a commit that actually resolves it is merged.
|
||||
|
||||
## Before implementation
|
||||
When you want to add a feature or fix a bug, **first have the design and policy reviewed in an Issue** (if it is not there, please make one). Without this step, there is a high possibility that the PR will not be merged even if it is implemented.
|
||||
|
||||
At this point, you also need to clarify the goals of the PR you will create, and make sure that the other members of the team are aware of them.
|
||||
PRs that do not have a clear set of do's and don'ts tend to be bloated and difficult to review.
|
||||
|
||||
Also, when you start implementation, assign yourself to the Issue (if you cannot do it yourself, ask another member to assign you). By expressing your intention to work the Issue, you can prevent conflicts in the work.
|
||||
|
||||
## Well-known branches
|
||||
- The **`main`** branch is tracking the latest release and used for production purposes.
|
||||
- The **`develop`** branch is where we work for the next release.
|
||||
- When you create a PR, basically target it to this branch. **But create a different branch**
|
||||
- The **`l10n_develop`** branch is reserved for localization management.
|
||||
- **`feature/*`** branches are reserved for the development of a specific feature
|
||||
|
||||
## Creating a PR
|
||||
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.
|
||||
- `fix` / `refactor` / `feat` / `enhance` / `perf` / `chore` etc. You are also welcome to use gitmoji. This is important as we use these to A) easier read the git history and B) generate our changelog. Without propper prefixing it is possible that your PR is rejected.
|
||||
- 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 which will be resolved by this PR, please include a reference to the Issue in the text. Good examples include `Closing: #21` or `Resolves: #21`
|
||||
- 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 formatting, tests and Lint are passed in advance.
|
||||
- You can run it with `pnpm run format`, `pnpm run test` and `pnpm run lint`. [See more info](#testing)
|
||||
- If this PR includes UI changes, please attach a screenshot in the text.
|
||||
|
||||
Thanks for your cooperation 🤗
|
||||
|
||||
## Reviewers guide
|
||||
Be willing to comment on the good points and not just the things you want fixed 💯
|
||||
|
||||
### Review perspective
|
||||
- Scope
|
||||
- Are the goals of the PR clear?
|
||||
- Is the granularity of the PR appropriate?
|
||||
- Security
|
||||
- Does merging this PR create a vulnerability?
|
||||
- Performance
|
||||
- Will merging this PR cause unexpected performance degradation?
|
||||
- Is there a more efficient way?
|
||||
- Testing
|
||||
- Does the test ensure the expected behavior?
|
||||
- Are there any omissions or gaps?
|
||||
- Does it check for anomalies?
|
||||
|
||||
## Deploy (SOON)
|
||||
The `/deploy` command by issue comment can be used to deploy the contents of a PR to the preview environment.
|
||||
```
|
||||
/deploy sha=<commit hash>
|
||||
```
|
||||
An actual domain will be assigned so you can test the federation.
|
||||
|
||||
## Merge
|
||||
|
||||
## Release
|
||||
### Release Instructions
|
||||
1. Commit version changes in the `develop` branch ([package.json](https://github.com/misskey-dev/misskey/blob/develop/package.json))
|
||||
2. Create a release PR.
|
||||
- Into `master` from `develop` branch.
|
||||
- The title must be in the format `Release: x.y.z`.
|
||||
- `x.y.z` is the new version you are trying to release.
|
||||
3. Deploy and perform a simple QA check. Also verify that the tests passed.
|
||||
4. Merge it.
|
||||
5. Create a [release of GitHub](https://github.com/misskey-dev/misskey/releases)
|
||||
- The target branch must be `master`
|
||||
- The tag name must be the version
|
||||
|
||||
## Development
|
||||
During development, it is useful to use the `yarn dev` command.
|
||||
This command monitors the server-side and client-side source files and automatically builds them if they are modified.
|
||||
In addition, it will also automatically start the Misskey server process.
|
||||
|
||||
|
||||
# THE FOLLOWING IS OUTDATED:
|
||||
|
||||
## Testing
|
||||
- Test codes are located in [`/test`](/test).
|
||||
|
||||
### Run test
|
||||
Create a config file.
|
||||
```
|
||||
cp test/test.yml .config/
|
||||
```
|
||||
Prepare DB/Redis for testing.
|
||||
```
|
||||
docker-compose -f test/docker-compose.yml up
|
||||
```
|
||||
Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`.
|
||||
|
||||
Run all test.
|
||||
```
|
||||
yarn test
|
||||
```
|
||||
|
||||
#### Run specify test
|
||||
```
|
||||
TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT="./test/tsconfig.json" yarn dlx mocha test/foo.ts --require ts-node/register
|
||||
```
|
||||
|
||||
### e2e tests
|
||||
TODO
|
||||
|
||||
## Continuous integration
|
||||
Misskey uses GitHub Actions for executing automated tests.
|
||||
Configuration files are located in [`/.github/workflows`](/.github/workflows).
|
||||
|
||||
## Vue
|
||||
Misskey uses Vue(v3) as its front-end framework.
|
||||
- Use TypeScript.
|
||||
- **When creating a new component, please use the Composition API (with [setup sugar](https://v3.vuejs.org/api/sfc-script-setup.html) and [ref sugar](https://github.com/vuejs/rfcs/discussions/369)) instead of the Options API.**
|
||||
- Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome.
|
||||
|
||||
## nirax
|
||||
niraxは、Misskeyで使用しているオリジナルのフロントエンドルーティングシステムです。
|
||||
**vue-routerから影響を多大に受けているので、まずはvue-routerについて学ぶことをお勧めします。**
|
||||
|
||||
### ルート定義
|
||||
ルート定義は、以下の形式のオブジェクトの配列です。
|
||||
|
||||
``` ts
|
||||
{
|
||||
name?: string;
|
||||
path: string;
|
||||
component: Component;
|
||||
query?: Record<string, string>;
|
||||
loginRequired?: boolean;
|
||||
hash?: string;
|
||||
globalCacheKey?: string;
|
||||
children?: RouteDef[];
|
||||
}
|
||||
```
|
||||
|
||||
> **Warning**
|
||||
> 現状、ルートは定義された順に評価されます。
|
||||
> たとえば、`/foo/:id`ルート定義の次に`/foo/bar`ルート定義がされていた場合、後者がマッチすることはありません。
|
||||
|
||||
### 複数のルーター
|
||||
vue-routerとの最大の違いは、niraxは複数のルーターが存在することを許可している点です。
|
||||
これにより、アプリ内ウィンドウでブラウザとは個別にルーティングすることなどが可能になります。
|
||||
|
||||
## Notes
|
||||
### How to resolve conflictions occurred at yarn.lock?
|
||||
|
||||
Just execute `yarn` to fix it.
|
||||
|
||||
### INSERTするときにはsaveではなくinsertを使用する
|
||||
#6441
|
||||
|
||||
### placeholder
|
||||
SQLをクエリビルダで組み立てる際、使用するプレースホルダは重複してはならない
|
||||
例えば
|
||||
``` ts
|
||||
query.andWhere(new Brackets(qb => {
|
||||
for (const type of ps.fileType) {
|
||||
qb.orWhere(`:type = ANY(note.attachedFileTypes)`, { type: type });
|
||||
}
|
||||
}));
|
||||
```
|
||||
と書くと、ループ中で`type`というプレースホルダが複数回使われてしまいおかしくなる
|
||||
だから次のようにする必要がある
|
||||
```ts
|
||||
query.andWhere(new Brackets(qb => {
|
||||
for (const type of ps.fileType) {
|
||||
const i = ps.fileType.indexOf(type);
|
||||
qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { [`type${i}`]: type });
|
||||
}
|
||||
}));
|
||||
```
|
||||
|
||||
### Not `null` in TypeORM
|
||||
```ts
|
||||
const foo = await Foos.findOne({
|
||||
bar: Not(null)
|
||||
});
|
||||
```
|
||||
のようなクエリ(`bar`が`null`ではない)は期待通りに動作しない。
|
||||
次のようにします:
|
||||
```ts
|
||||
const foo = await Foos.findOne({
|
||||
bar: Not(IsNull())
|
||||
});
|
||||
```
|
||||
|
||||
### `null` in SQL
|
||||
SQLを発行する際、パラメータが`null`になる可能性のある場合はSQL文を出し分けなければならない
|
||||
例えば
|
||||
``` ts
|
||||
query.where('file.folderId = :folderId', { folderId: ps.folderId });
|
||||
```
|
||||
という処理で、`ps.folderId`が`null`だと結果的に`file.folderId = null`のようなクエリが発行されてしまい、これは正しいSQLではないので期待した結果が得られない
|
||||
だから次のようにする必要がある
|
||||
``` ts
|
||||
if (ps.folderId) {
|
||||
query.where('file.folderId = :folderId', { folderId: ps.folderId });
|
||||
} else {
|
||||
query.where('file.folderId IS NULL');
|
||||
}
|
||||
```
|
||||
|
||||
### `[]` in SQL
|
||||
SQLを発行する際、`IN`のパラメータが`[]`(空の配列)になる可能性のある場合はSQL文を出し分けなければならない
|
||||
例えば
|
||||
``` ts
|
||||
const users = await Users.find({
|
||||
id: In(userIds)
|
||||
});
|
||||
```
|
||||
という処理で、`userIds`が`[]`だと結果的に`user.id IN ()`のようなクエリが発行されてしまい、これは正しいSQLではないので期待した結果が得られない
|
||||
だから次のようにする必要がある
|
||||
``` ts
|
||||
const users = userIds.length > 0 ? await Users.find({
|
||||
id: In(userIds)
|
||||
}) : [];
|
||||
```
|
||||
|
||||
### 配列のインデックス in SQL
|
||||
SQLでは配列のインデックスは**1始まり**。
|
||||
`[a, b, c]`の `a`にアクセスしたいなら`[0]`ではなく`[1]`と書く
|
||||
|
||||
### null IN
|
||||
nullが含まれる可能性のあるカラムにINするときは、そのままだとおかしくなるのでORなどでnullのハンドリングをしよう。
|
||||
|
||||
### `undefined`にご用心
|
||||
MongoDBの時とは違い、findOneでレコードを取得する時に対象レコードが存在しない場合 **`undefined`** が返ってくるので注意。
|
||||
MongoDBは`null`で返してきてたので、その感覚で`if (x === null)`とか書くとバグる。代わりに`if (x == null)`と書いてください
|
||||
|
||||
### Migration作成方法
|
||||
packages/backendで:
|
||||
```sh
|
||||
pnpm dlx typeorm migration:generate -d ormconfig.js -o <migration name>
|
||||
```
|
||||
|
||||
- 生成後、ファイルをmigration下に移してください
|
||||
- 作成されたスクリプトは不必要な変更を含むため除去してください
|
||||
|
||||
### コネクションには`markRaw`せよ
|
||||
**Vueのコンポーネントのdataオプションとして**misskey.jsのコネクションを設定するとき、必ず`markRaw`でラップしてください。インスタンスが不必要にリアクティブ化されることで、misskey.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。
|
||||
|
||||
### JSONのimportに気を付けよう
|
||||
TypeScriptでjsonをimportすると、tscでコンパイルするときにそのjsonファイルも一緒にdistディレクトリに吐き出されてしまう。この挙動により、意図せずファイルの書き換えが発生することがあるので、jsonをimportするときは書き換えられても良いものかどうか確認すること。書き換えされて欲しくない場合は、importで読み込むのではなく、`fs.readFileSync`などの関数を使って読み込むようにすればよい。
|
||||
|
||||
### コンポーネントのスタイル定義でmarginを持たせない
|
||||
コンポーネント自身がmarginを設定するのは問題の元となることはよく知られている
|
||||
marginはそのコンポーネントを使う側が設定する
|
||||
|
||||
## その他
|
||||
### HTMLのクラス名で follow という単語は使わない
|
||||
広告ブロッカーで誤ってブロックされる
|
33
COPYING
Normal file
33
COPYING
Normal file
|
@ -0,0 +1,33 @@
|
|||
Unless specified otherwise, the entirety of this repository is subject to the following:
|
||||
Copyright © 2014-2023 syuilo and contributors
|
||||
Copyright © 2022-2023 Kainoa Kanter and contributors
|
||||
|
||||
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
|
||||
|
||||
---
|
||||
|
||||
These specific configuration directories:
|
||||
|
||||
- .config/
|
||||
- custom/assets/
|
||||
|
||||
and their contents are
|
||||
Copyright © 2022-2023 Kainoa Kanter and contributors
|
||||
|
||||
And are distributed under The Apache License, Version 2.0, you should have received a copy of the license file as LICENSE in each specified directory.
|
||||
|
||||
---
|
||||
|
||||
Firefish includes several third-party open-source softwares and software libraries.
|
||||
|
||||
RsaSignature2017 implementation by Transmute Industries Inc
|
||||
License: MIT
|
||||
https://github.com/transmute-industries/RsaSignature2017/blob/master/LICENSE
|
||||
|
||||
Machine learning model for sensitive images by Infinite Red, Inc.
|
||||
License: MIT
|
||||
https://github.com/infinitered/nsfwjs/blob/master/LICENSE
|
||||
|
||||
Licenses for all softwares and software libraries installed via the Node Package Manager ("npm") can be found by running the following shell command in the root directory of this repository:
|
||||
|
||||
pnpm licenses list
|
73
Dockerfile
Normal file
73
Dockerfile
Normal file
|
@ -0,0 +1,73 @@
|
|||
## Install dev and compilation dependencies, build files
|
||||
FROM alpine:3.18 as build
|
||||
WORKDIR /firefish
|
||||
|
||||
# Install compilation dependencies
|
||||
RUN apk add --no-cache --no-progress git alpine-sdk python3 nodejs-current npm rust cargo vips
|
||||
|
||||
# Copy only the cargo dependency-related files first, to cache efficiently
|
||||
COPY packages/backend/native-utils/Cargo.toml packages/backend/native-utils/Cargo.toml
|
||||
COPY packages/backend/native-utils/Cargo.lock packages/backend/native-utils/Cargo.lock
|
||||
COPY packages/backend/native-utils/src/lib.rs packages/backend/native-utils/src/
|
||||
COPY packages/backend/native-utils/migration/Cargo.toml packages/backend/native-utils/migration/Cargo.toml
|
||||
COPY packages/backend/native-utils/migration/src/lib.rs packages/backend/native-utils/migration/src/
|
||||
|
||||
# Install cargo dependencies
|
||||
RUN cargo fetch --locked --manifest-path /firefish/packages/backend/native-utils/Cargo.toml
|
||||
|
||||
# Copy only the dependency-related files first, to cache efficiently
|
||||
COPY package.json pnpm*.yaml ./
|
||||
COPY packages/backend/package.json packages/backend/package.json
|
||||
COPY packages/client/package.json packages/client/package.json
|
||||
COPY packages/sw/package.json packages/sw/package.json
|
||||
COPY packages/firefish-js/package.json packages/firefish-js/package.json
|
||||
COPY packages/megalodon/package.json packages/megalodon/package.json
|
||||
COPY packages/backend/native-utils/package.json packages/backend/native-utils/package.json
|
||||
COPY packages/backend/native-utils/npm/linux-x64-musl/package.json packages/backend/native-utils/npm/linux-x64-musl/package.json
|
||||
COPY packages/backend/native-utils/npm/linux-arm64-musl/package.json packages/backend/native-utils/npm/linux-arm64-musl/package.json
|
||||
|
||||
# Configure corepack and pnpm, and install dev mode dependencies for compilation
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm i --frozen-lockfile
|
||||
|
||||
# Copy in the rest of the native-utils rust files
|
||||
COPY packages/backend/native-utils packages/backend/native-utils/
|
||||
|
||||
# Compile native-utils
|
||||
RUN pnpm run --filter native-utils build
|
||||
|
||||
# Copy in the rest of the files to compile
|
||||
COPY . ./
|
||||
RUN env NODE_ENV=production sh -c "pnpm run --filter '!native-utils' build && pnpm run gulp"
|
||||
|
||||
# Trim down the dependencies to only those for production
|
||||
RUN pnpm i --prod --frozen-lockfile
|
||||
|
||||
## Runtime container
|
||||
FROM alpine:3.18
|
||||
WORKDIR /firefish
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache --no-progress tini ffmpeg vips-dev zip unzip nodejs-current
|
||||
|
||||
COPY . ./
|
||||
|
||||
COPY --from=build /firefish/packages/megalodon /firefish/packages/megalodon
|
||||
|
||||
# Copy node modules
|
||||
COPY --from=build /firefish/node_modules /firefish/node_modules
|
||||
COPY --from=build /firefish/packages/backend/node_modules /firefish/packages/backend/node_modules
|
||||
COPY --from=build /firefish/packages/sw/node_modules /firefish/packages/sw/node_modules
|
||||
COPY --from=build /firefish/packages/client/node_modules /firefish/packages/client/node_modules
|
||||
COPY --from=build /firefish/packages/firefish-js/node_modules /firefish/packages/firefish-js/node_modules
|
||||
|
||||
# Copy the finished compiled files
|
||||
COPY --from=build /firefish/built /firefish/built
|
||||
COPY --from=build /firefish/packages/backend/built /firefish/packages/backend/built
|
||||
COPY --from=build /firefish/packages/backend/assets/instance.css /firefish/packages/backend/assets/instance.css
|
||||
COPY --from=build /firefish/packages/backend/native-utils/built /firefish/packages/backend/native-utils/built
|
||||
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
ENV NODE_ENV=production
|
||||
VOLUME "/firefish/files"
|
||||
ENTRYPOINT [ "/sbin/tini", "--" ]
|
||||
CMD [ "pnpm", "run", "migrateandstart" ]
|
166
FIREFISH.md
Normal file
166
FIREFISH.md
Normal file
|
@ -0,0 +1,166 @@
|
|||
# All the changes to Firefish from stock Misskey
|
||||
|
||||
> **Warning**
|
||||
> This list is incomplete. Please check the [Releases](https://gitlab.prometheus.systems/firefish/firefish/releases) and [Changelog](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/CHANGELOG.md) for a more complete list of changes. There have been [>4000 commits (laggy link)](https://gitlab.prometheus.systems/firefish/firefish/compare/700a7110f7e34f314b070987aa761c451ec34efc...develop) since we forked Misskey!
|
||||
|
||||
## Planned
|
||||
|
||||
- Stucture
|
||||
- Rewrite backend in Rust and [Rocket](https://rocket.rs/)
|
||||
- Function
|
||||
- User "choices" (recommended users) and featured hashtags like Mastodon and Soapbox
|
||||
- Join Reason system like Mastodon/Pleroma
|
||||
- Option to publicize server blocks
|
||||
- More antenna options
|
||||
- Groups
|
||||
|
||||
## Work in progress
|
||||
|
||||
- Better Messaging UI
|
||||
- Better API Documentation
|
||||
- Remote follow button
|
||||
- Improve accesibility
|
||||
- Timeline filters
|
||||
- Events
|
||||
- Fully revamp non-logged-in screen
|
||||
- Optionally use [ScyllaDB](https://www.scylladb.com/open-source-nosql-database/) for storing notes
|
||||
|
||||
## Implemented
|
||||
|
||||
- A lot of general bugfixes
|
||||
- pnpm instead of yarn
|
||||
- Fix Dockerfile @hanna
|
||||
- Upgrade packages with security vunrabilities
|
||||
- Saner defaults
|
||||
- Fediverse account migration
|
||||
- Recommended servers timeline
|
||||
- OCR image captioning
|
||||
- Improve mobile UX
|
||||
- Swipe through pages on mobile
|
||||
- Redesigned mobile bottom nav bar
|
||||
- Post button on TL
|
||||
- Star as default reaction
|
||||
- Like/star button
|
||||
- Rosé Pine by default (+ non-themable elements made Rosé Pine)
|
||||
- Better sidebar/navbar
|
||||
- Better intro tutorial/onboarding
|
||||
- Add back groups
|
||||
- Integrate groups UI into chats UI
|
||||
- MOTD (customizable by admins!)
|
||||
- Custom randomized splash icons
|
||||
- Self hosted, newly designed error images
|
||||
- Illustrated by [Henki](https://www.youtube.com/c/Henkiwashere)!
|
||||
- Licensed under the CC-BY-SA 4.0.
|
||||
- Better timeline top bar
|
||||
- Improved note style
|
||||
- Make more of the post clickable like every other SNS
|
||||
- No more details tag for reply attachments
|
||||
- Better CW button
|
||||
- Mark as read from notifications widget
|
||||
- Less cluttered notification summary
|
||||
- Better welcome screen (not logged in)
|
||||
- vue-plyr as video/audio player
|
||||
- Ability to turn off "Connection lost" message
|
||||
- Raw server info only for moderators
|
||||
- New spinner animation
|
||||
- Spinner instead of "Loading..."
|
||||
- Always signToActivityPubGet
|
||||
- Spacing on group items
|
||||
- Quotes have solid border
|
||||
- Reply limit bug fixed
|
||||
- Make showing the update popup optional
|
||||
- Improve PWA manifest
|
||||
- Fix incoming chat scrolling globally
|
||||
- Update notifier
|
||||
- Allow admins to set logo URL via admin settings
|
||||
- Allow importing follows from Pixelfed
|
||||
- Phosphor icons instead of FontAwesome
|
||||
- Fully deprecate MkEmojiPickerWindow in favor of MkEmojiPickerDialog
|
||||
- Link hover effect
|
||||
- Replace all `$ts` with i18n
|
||||
- AVIF support
|
||||
- Page drafts
|
||||
- Patron list
|
||||
- Animations respect reduced motion
|
||||
- Undo renote button inside original note
|
||||
- Custom locales
|
||||
- Obliteration of Ai-chan
|
||||
- Switch to [Firefish.js](https://gitlab.prometheus.systems/firefish/firefish.js)
|
||||
- Woozy mode 🥴
|
||||
- Improve blocking servers
|
||||
- Release notes
|
||||
- New post style
|
||||
- Admins set default reaction emoji
|
||||
- Allows custom emoji
|
||||
- Fix lint errors
|
||||
- Use Rome instead of ESLint
|
||||
- Mastodon API support
|
||||
- More antenna options
|
||||
- New dashboard
|
||||
- Backfill follower counts
|
||||
- Compile time compression
|
||||
- Sonic search
|
||||
- Popular color schemes, including Nord, Gruvbox, and Catppuccin
|
||||
- Non-nyaify cat mode
|
||||
- Post imports from other Firefish/Misskey/Mastodon/Pleroma/Akkoma servers
|
||||
- Improve Classic mode
|
||||
- Proper Helm/Kubernetes config
|
||||
- Multiple boost visibilities
|
||||
- Improve system emails
|
||||
- Mod mail
|
||||
- Focus trapping and button labels
|
||||
- Meilisearch with filters
|
||||
- Post editing
|
||||
- Display remaining time on rate-limits
|
||||
- Proper 2FA input dialog
|
||||
- Let moderators see moderation nodes
|
||||
- Non-mangled unicode emojis
|
||||
- Skin tone selection support
|
||||
- [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative
|
||||
- Link verification
|
||||
- Importing posts from other Firefish/Misskey/Mastodon/Akkoma/Pleroma instances
|
||||
|
||||
## Implemented (remote)
|
||||
|
||||
- MissV: [fix Misskey Forkbomb](https://code.vtopia.live/Vtopia/MissV/commit/40b23c070bd4adbb3188c73546c6c625138fb3c1)
|
||||
- [Make showing ads optional](https://github.com/misskey-dev/misskey/pull/8996)
|
||||
- [Tapping avatar in mobile opens account modal](https://github.com/misskey-dev/misskey/pull/9056)
|
||||
- [OAuth bearer token authentication](https://github.com/misskey-dev/misskey/pull/9021)
|
||||
- [Styled Repair Tools](https://github.com/misskey-dev/misskey/pull/8956)
|
||||
- [Option to make enter send message](https://github.com/misskey-dev/misskey/pull/8954)
|
||||
- [Autocomplete in messaging](https://github.com/misskey-dev/misskey/pull/8955)
|
||||
- [Profile background as banner](https://codeberg.org/Freeplay/Misskey-Tweaks/src/branch/main/snippets/profile-background.styl)
|
||||
- [Star is generic like/favorite](https://github.com/JakeMBauer/Misskey-Extras/blob/master/patches/star-is-like.patch)
|
||||
- 👍 also triggers generic like/favorite
|
||||
- [Add additional background for acrylic popups if backdrop-filter is unsupported](https://github.com/misskey-dev/misskey/pull/8671)
|
||||
- [Add parameters to MFM rotate](https://github.com/misskey-dev/misskey/pull/8549)
|
||||
- Many changes from [FoundKey](https://akkoma.dev/FoundKeyGang/FoundKey)
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/0ece67b04c3f0365057624c1068808276ccab981: refactor pages/auth.form.vue to composition API
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/4bc9610d8bf5af736b5e89e4782395705de45d7d: remove unnecessary joins
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/9ee609d70082f7a6dc119a5d83c0e7c5e1208676: enhance privacy of notes
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/0fec6e10477b1c1b95d9469fbaf4e249a3722f12: remove ms dependency
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/46fff77accbe8bf0fd3cc88170d67b997bf2bdc3: client uses new API for child notes depth
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/c35372a20d22cddb75e93a0b407f2b652cd7faf0: pack children without detail
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/aca724e0bfff3e58b4d273f3ee744e3f3aa9c39b: enable to fetch replies recursively
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/2fe64c11502fd8d89c126558cd715e095c83754e: Refactor components/page/page.textarea.vue to composition API
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/6d3181f9835955e5b79bde5484c74bd70e7f9535: Refactor components/page/page.text.vue to composition API
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/b630cd7eacd695bb705e6748c87f38425ec4ed45: refactor: add NoteReactions.packMany
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/3fe351df6d4e21f7748c46adfa6ca165abd030c0: fix: catch errors from packing with detail
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/63591da33e233b2ed0ab331ae6bb3c9eff5020ae: refactor: colours in queue chart
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/0f6d94f1e7e1f58cfbf8d07e5f835f8de626842e: backend: improve mutes and blocks
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/e2bf2715a6462ed377b033956d65260157f042ea: fix spelling error
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/09a7eabda137e77f81ab31f65d69329670693c8d: backend: fix lint "no-throw-literal"
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/4fbe2e065e75ed3e5b4dfdfd4be3baa03cc447c3: client: fix lint "quotes"
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/585e4f5c42cfafb6cdf7eb601ab435d6a4d85a96: fix textarea not updating properly
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/30d8bc9259cb6b72ed76d67b21dbb4cdceca8327: refactor: welcome.setup.vue to composition api
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/751921e24f37ed707fe44a40d88eebb1299efa35: make emoji picker case insensitive
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/298febeb9c9501e3e3df16982c08657d1da474e0: enhance: add re-collapsing to quoted notes
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/b0fdedb264db87575063abed45e52ad71ce4a6af: fix lints in folder.vue
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/6fed87f85d132304eb84b0a59b84dce299a1822f: fix pagination.vue lints
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/384e8c49b738f576ba8843296de6cebf01c1b247: server: allow to like own gallery posts
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/4c5aa9e53887cca5561fcec6ab0754e018f589a5: server: allow to like own pages
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/923c93da1228458dd65be47483c198a1a9191bcf: use await for notes.countBy
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/ca90cedba0a0704b503c2778694230f5a7dfbace: server: reduce dead instance detection to 7 days
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/e9ab42c10afb4e27516c2d2b5e3e06630efe9edd: Alt text in image viewer
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/ed9d4023d41bba7c4ac53a1a3422246feed37de2: add argon2 support
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/c414f24a2c123774246c7eca65edda4d3afaf8b3: feat: per-user renote muting
|
661
LICENSE
Normal file
661
LICENSE
Normal file
|
@ -0,0 +1,661 @@
|
|||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
1
Procfile
Normal file
1
Procfile
Normal file
|
@ -0,0 +1 @@
|
|||
web: NODE_ENV=production npm start
|
282
README.md
Normal file
282
README.md
Normal file
|
@ -0,0 +1,282 @@
|
|||
# ️:warning: Repo has moved!
|
||||
|
||||
https://gitlab.prometheus.systems/firefish/firefish/
|
||||
|
||||
<div align="center">
|
||||
<a href="https://joinfirefish.org/">
|
||||
<img src="./title.svg" alt="Firefish logo" style="border-radius:50%" width="400"/>
|
||||
</a>
|
||||
|
||||
**🌎 **[Firefish](https://joinfirefish.org/)** is an open source, decentralized social media platform that's free forever! 🚀**
|
||||
|
||||
[![no github badge](https://nogithub.codeberg.page/badge.svg)](https://nogithub.codeberg.page/)
|
||||
<!-- [![status badge](https://ci.codeberg.org/api/badges/firefish/firefish/status.svg)](https://ci.codeberg.org/firefish/firefish) -->
|
||||
[![opencollective badge](https://opencollective.com/firefish/tiers/badge.svg)](https://opencollective.com/Firefish)
|
||||
[![liberapay badge](https://img.shields.io/liberapay/receives/ThatOneCalculator?logo=liberapay)](https://liberapay.com/ThatOneCalculator)
|
||||
[![translate-badge](https://hosted.weblate.org/widgets/firefish/-/svg-badge.svg)](https://hosted.weblate.org/engage/firefish/)
|
||||
<!-- [![docker badge](https://img.shields.io/docker/pulls/thatonecalculator/firefish?logo=docker)](https://hub.docker.com/r/thatonecalculator/firefish) -->
|
||||
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](./CODE_OF_CONDUCT.md)
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<img src="./animated.svg" align="right" height="320px"/>
|
||||
|
||||
# ✨ About Firefish
|
||||
|
||||
- Firefish is based off of Misskey, a powerful microblogging server on ActivityPub with features such as emoji reactions, a customizable web UI, rich chatting, and much more!
|
||||
- Firefish adds many quality of life changes and bug fixes for users and server admins alike.
|
||||
- Read **[this document](./FIREFISH.md)** all for current and future differences.
|
||||
- Notable differences:
|
||||
- Improved UI/UX (especially on mobile)
|
||||
- Post editing
|
||||
- Content importing
|
||||
- Improved notifications
|
||||
- Improved server security
|
||||
- Improved accessibility
|
||||
- Improved threads
|
||||
- Recommended Servers timeline
|
||||
- OCR image captioning
|
||||
- New and improved Groups
|
||||
- Better intro tutorial
|
||||
- Compatibility with Mastodon clients/apps
|
||||
- Backfill user information
|
||||
- Advanced search
|
||||
- Many more user and admin settings
|
||||
- [So much more!](./FIREFISH.md)
|
||||
|
||||
</div>
|
||||
|
||||
<div style="clear: both;"></div>
|
||||
|
||||
# 🥂 Links
|
||||
|
||||
### Want to get involved? Great!
|
||||
|
||||
- If you have the means to, [donations](https://opencollective.com/Firefish) are a great way to keep us going.
|
||||
- If you know how to program in TypeScript, Vue, or Rust, read the [contributing](./CONTRIBUTING.md) document.
|
||||
- If you know a non-English language, translating Firefish on [Weblate](https://hosted.weblate.org/engage/firefish/) help bring Firefish to more people. No technical experience needed!
|
||||
- Want to write/report about us, have any professional inquiries, or just have questions to ask? Contact us [here!](https://joinfirefish.org/contact/)
|
||||
|
||||
### All links
|
||||
|
||||
- 🌐 Homepage: <https://joinfirefish.org>
|
||||
- 💸 Donations:
|
||||
- OpenCollective: <https://opencollective.com/Firefish>
|
||||
- Liberapay: <https://liberapay.com/ThatOneCalculator>
|
||||
- Donate publicly to get your name on the Patron list!
|
||||
- 🚢 Flagship server: <https://firefish.social>
|
||||
- 💁 Matrix support room: <https://matrix.to/#/#firefish:matrix.fedibird.com>
|
||||
- 📣 Official account: <https://i.firefish.cloud/@firefish>
|
||||
- 📜 Server list: <https://joinfirefish.org/join>
|
||||
- ✍️ Weblate: <https://hosted.weblate.org/engage/firefish/>
|
||||
- ️️📬 Contact: <https://joinfirefish.org/contact/>
|
||||
|
||||
# 🌠 Getting started
|
||||
|
||||
Want to just join a Firefish server? View the list here, pick one, and join:
|
||||
|
||||
### https://joinfirefish.org/join
|
||||
|
||||
---
|
||||
|
||||
Want to make your own? Keep reading!
|
||||
|
||||
This guide will work for both **starting from scratch** and **migrating from Misskey**.
|
||||
|
||||
## 🔰 Easy installers
|
||||
|
||||
If you have access to a server that supports one of the sources below, I recommend you use it! Note that these methods *won't* allow you to migrate from Misskey without manual intervention.
|
||||
|
||||
<!-- [![Install on the Arch User Repository](https://pool.jortage.com/voringme/misskey/ba2a5c07-f078-43f1-8483-2e01acca9c40.png)](https://aur.archlinux.org/packages/firefish) -->
|
||||
|
||||
[![Install on Ubuntu](https://pool.jortage.com/voringme/misskey/3b62a443-1b44-45cf-8f9e-f1c588f803ed.png)](https://gitlab.prometheus.systems/firefish/ubuntu-bash-install) [![Install Firefish with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=firefish)
|
||||
|
||||
## 🛳️ Containerization
|
||||
|
||||
- [🐳 How to run Firefish with Docker](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/docs/docker.md)
|
||||
- [🛞 How to run Firefish with Kubernetes/Helm](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/docs/kubernetes.md)
|
||||
|
||||
## 🧑💻 Dependencies
|
||||
|
||||
- 🐢 At least [NodeJS](https://nodejs.org/en/) v18.16.0 (v20 recommended)
|
||||
- 🐘 At least [PostgreSQL](https://www.postgresql.org/) v12 (v14 recommended)
|
||||
- 🍱 At least [Redis](https://redis.io/) v6 (v7 recommended)
|
||||
- Web Proxy (one of the following)
|
||||
- 🍀 Nginx (recommended)
|
||||
- 🦦 Caddy
|
||||
- 🪶 Apache
|
||||
- ⚡ [libvips](https://www.libvips.org/)
|
||||
|
||||
### 😗 Optional dependencies
|
||||
|
||||
- [FFmpeg](https://ffmpeg.org/) for video transcoding
|
||||
- Full text search (one of the following)
|
||||
- 🦔 [Sonic](https://crates.io/crates/sonic-server)
|
||||
- [MeiliSearch](https://www.meilisearch.com/)
|
||||
- [ElasticSearch](https://www.elastic.co/elasticsearch/)
|
||||
- Caching server (one of the following)
|
||||
- 🐲 [DragonflyDB](https://www.dragonflydb.io/) (recommended)
|
||||
- 👻 [KeyDB](https://keydb.dev/)
|
||||
- 🍱 Another [Redis](https://redis.io/) server
|
||||
|
||||
### 🏗️ Build dependencies
|
||||
|
||||
- 🦀 At least [Rust](https://www.rust-lang.org/) v1.68.0
|
||||
- 🦬 C/C++ compiler & build tools
|
||||
- `build-essential` on Debian/Ubuntu Linux
|
||||
- `base-devel` on Arch Linux
|
||||
- 🐍 [Python 3](https://www.python.org/)
|
||||
|
||||
## 👀 Get folder ready
|
||||
|
||||
```sh
|
||||
git clone https://gitlab.prometheus.systems/firefish/firefish.git
|
||||
cd firefish/
|
||||
```
|
||||
|
||||
> **Note**
|
||||
> By default, you're on the develop branch. Run `git checkout main` or `git checkout beta` to switch to the Main/Beta branches.
|
||||
|
||||
## 📩 Install dependencies
|
||||
|
||||
```sh
|
||||
# nvm install 19 && nvm use 19
|
||||
corepack enable
|
||||
corepack prepare pnpm@latest --activate
|
||||
# To build without TensorFlow, append --no-optional
|
||||
pnpm i # --no-optional
|
||||
```
|
||||
|
||||
### pm2
|
||||
|
||||
To install pm2 run:
|
||||
|
||||
```
|
||||
npm i -g pm2
|
||||
pm2 install pm2-logrotate
|
||||
```
|
||||
|
||||
> **Note**
|
||||
> [`pm2-logrotate`](https://github.com/keymetrics/pm2-logrotate/blob/master/README.md) ensures that log files don't infinitely gather size, as Firefish produces a lot of logs.
|
||||
|
||||
## 🐘 Create database
|
||||
|
||||
In PostgreSQL (`psql`), run the following command:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE firefish WITH encoding = 'UTF8';
|
||||
```
|
||||
|
||||
or run the following from the command line:
|
||||
|
||||
```sh
|
||||
psql postgres -c "create database firefish with encoding = 'UTF8';"
|
||||
```
|
||||
|
||||
In Firefish's directory, fill out the `db` section of `.config/default.yml` with the correct information, where the `db` key is `firefish`.
|
||||
|
||||
## 💰 Caching server
|
||||
|
||||
If you experience a lot of traffic, it's a good idea to set up another Redis-compatible caching server. If you don't set one one up, it'll fall back to the mandatory Redis server. DragonflyDB is the recommended option due to its unrivaled performance and ease of use.
|
||||
|
||||
## 🔎 Set up search
|
||||
|
||||
### 🦔 Sonic
|
||||
|
||||
Sonic is better suited for self hosters with smaller deployments. It uses almost no resources, barely any any disk space, and is relatively fast.
|
||||
|
||||
Follow sonic's [installation guide](https://github.com/valeriansaliou/sonic#installation)
|
||||
|
||||
> **Note**
|
||||
> If you use IPv4: in Sonic's directory, edit the `config.cfg` file to change `inet` to `"0.0.0.0:1491"`.
|
||||
|
||||
In Firefish's directory, fill out the `sonic` section of `.config/default.yml` with the correct information.
|
||||
|
||||
### Meilisearch
|
||||
|
||||
Meilisearch is better suited for larger deployments. It's faster but uses far more resources and disk space.
|
||||
|
||||
Follow Meilisearch's [quick start guide](https://www.meilisearch.com/docs/learn/getting_started/quick_start)
|
||||
|
||||
In Firefish's directory, fill out the `meilisearch` section of `.config/default.yml` with the correct information.
|
||||
|
||||
### ElasticSearch
|
||||
|
||||
Please don't use ElasticSearch unless you already have an ElasticSearch setup and want to continue using it for Firefish. ElasticSearch is slow, heavy, and offers very few benefits over Sonic/Meilisearch.
|
||||
|
||||
## 💅 Customize
|
||||
|
||||
- To add custom CSS for all users, edit `./custom/assets/instance.css`.
|
||||
- To add static assets (such as images for the splash screen), place them in the `./custom/assets/` directory. They'll then be available on `https://yourserver.tld/static-assets/filename.ext`.
|
||||
- To add custom locales, place them in the `./custom/locales/` directory. If you name your custom locale the same as an existing locale, it will overwrite it. If you give it a unique name, it will be added to the list. Also make sure that the first part of the filename matches the locale you're basing it on. (Example: `en-FOO.yml`)
|
||||
- To add custom error images, place them in the `./custom/assets/badges` directory, replacing the files already there.
|
||||
- To add custom sounds, place only mp3 files in the `./custom/assets/sounds` directory.
|
||||
- To update custom assets without rebuilding, just run `pnpm run gulp`.
|
||||
|
||||
## 🧑🔬 Configuring a new server
|
||||
|
||||
- Run `cp .config/example.yml .config/default.yml`
|
||||
- Edit `.config/default.yml`, making sure to fill out required fields.
|
||||
- Also copy and edit `.config/docker_example.env` to `.config/docker.env` if you're using Docker.
|
||||
|
||||
## 🚚 Migrating from Misskey/FoundKey to Firefish
|
||||
|
||||
For migrating from Misskey v13, Misskey v12, and FoundKey, read [this document](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/docs/migrate.md).
|
||||
|
||||
## 🌐 Web proxy
|
||||
|
||||
### 🍀 Nginx (recommended)
|
||||
|
||||
- Run `sudo cp ./firefish.nginx.conf /etc/nginx/sites-available/ && cd /etc/nginx/sites-available/`
|
||||
- Edit `firefish.nginx.conf` to reflect your server properly
|
||||
- Run `sudo ln -s ./firefish.nginx.conf ../sites-enabled/firefish.nginx.conf`
|
||||
- Run `sudo nginx -t` to validate that the config is valid, then restart the NGINX service.
|
||||
|
||||
### 🦦 Caddy
|
||||
|
||||
- Add the following block to your `Caddyfile`, replacing `example.tld` with your own domain:
|
||||
```caddy
|
||||
example.tld {
|
||||
reverse_proxy http://127.0.0.1:3000
|
||||
}
|
||||
```
|
||||
- Reload your caddy configuration
|
||||
|
||||
### 🪶 Apache
|
||||
|
||||
> **Warning**
|
||||
> Apache has some known problems with Firefish. Only use it if you have to.
|
||||
|
||||
- Run `sudo cp ./firefish.apache.conf /etc/apache2/sites-available/ && cd /etc/apache2/sites-available/`
|
||||
- Edit `firefish.apache.conf` to reflect your server properly
|
||||
- Run `sudo a2ensite firefish.apache` to enable the site
|
||||
- Run `sudo service apache2 restart` to reload apache2 configuration
|
||||
## 🚀 Build and launch!
|
||||
|
||||
### 🐢 NodeJS + pm2
|
||||
|
||||
#### `git pull` and run these steps to update Firefish in the future!
|
||||
|
||||
```sh
|
||||
# git pull
|
||||
pnpm install
|
||||
NODE_ENV=production pnpm run build && pnpm run migrate
|
||||
pm2 start "NODE_ENV=production pnpm run start" --name Firefish
|
||||
```
|
||||
|
||||
## 😉 Tips & Tricks
|
||||
|
||||
- When editing the config file, please don't fill out the settings at the bottom. They're designed *only* for managed hosting, not self hosting. Those settings are much better off being set in Firefish's control panel.
|
||||
- Port 3000 (used in the default config) might be already used on your server for something else. To find an open port for Firefish, run `for p in {3000..4000}; do ss -tlnH | tr -s ' ' | cut -d" " -sf4 | grep -q "${p}$" || echo "${p}"; done | head -n 1`. Replace 3000 with the minimum port and 4000 with the maximum port if you need it.
|
||||
- I'd recommend you use a S3 Bucket/CDN for Object Storage, especially if you use Docker.
|
||||
- I'd ***strongly*** recommend against using CloudFlare, but if you do, make sure to turn code minification off.
|
||||
- For push notifications, run `npx web-push generate-vapid-keys`, then put the public and private keys into Control Panel > General > ServiceWorker.
|
||||
- For translations, make a [DeepL](https://deepl.com) account and generate an API key, then put it into Control Panel > General > DeepL Translation.
|
||||
- To add another admin account:
|
||||
- Go to the user's page > 3 Dots > About > Moderation > turn on "Moderator"
|
||||
- Go back to Overview > click the clipboard icon next to the ID
|
||||
- Run `psql -d firefish` (or whatever the database name is)
|
||||
- Run `UPDATE "user" SET "isAdmin" = true WHERE id='999999';` (replace `999999` with the copied ID)
|
||||
- Restart your Firefish server
|
119
RELEASE_NOTES.md
Normal file
119
RELEASE_NOTES.md
Normal file
|
@ -0,0 +1,119 @@
|
|||
# Firefish
|
||||
|
||||
Welcome to the new era of FIREFISH!
|
||||
|
||||
<img src="https://gitlab.prometheus.systems/firefish/firefish/-/raw/develop/animated.svg" height="320px"/>
|
||||
|
||||
# Changelog
|
||||
|
||||
## Major changes from last release candidate
|
||||
|
||||
- Firefish branding and [new repo](https://gitlab.prometheus.systems/firefish/firefish)!
|
||||
- Far better Mastodon API support
|
||||
- Edits are now non-experimental
|
||||
- Support for secondary cache server
|
||||
- Link verification with `rel=me`
|
||||
- Store antennas in cache
|
||||
- Post imports with media
|
||||
- Sytle fixes
|
||||
- More translations
|
||||
- Performance upgrades
|
||||
- Bug fixes
|
||||
- Faster build
|
||||
- [FoundKey](https://genau.qwertqwefsday.eu/notes/9h0lqlg05m) -> Firefish migration fixes
|
||||
|
||||
## Major changes from stable
|
||||
|
||||
All of the above, plus:
|
||||
|
||||
- Post editing
|
||||
- Post imports
|
||||
- New post design
|
||||
- New header design
|
||||
- Better accessibility
|
||||
- Server silences
|
||||
- Modmail
|
||||
- New MFM effects
|
||||
- Meilisearch search engine
|
||||
- Channel search
|
||||
- Improved system emails
|
||||
- cuid2 IDs
|
||||
- Emoji skin tones
|
||||
- New 2FA flow
|
||||
- Reduced visual clutter
|
||||
- Deck view improvements
|
||||
|
||||
# Upgrading
|
||||
|
||||
## If upgrading from v13 (old stable)
|
||||
|
||||
**In addition to the rest of the steps after this**:
|
||||
|
||||
- Install the Rust toolchain (v1.68.0 or higher): <https://www.rust-lang.org/tools/install>
|
||||
|
||||
- (Optional) install Meilisearch to use as a search engine instead of Sonic: <https://www.meilisearch.com/>
|
||||
|
||||
- Replace your config file (`.config/default.yml`) with a blank version of the example (`.config/example.yml`) and re-enter the information. This will make things easier.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Upgrade to at least Node v20.3.1 (v20.4.0 recommended).
|
||||
|
||||
- (Optional, recommended) install DragonflyDB and configure under `cacheServer`: <https://www.dragonflydb.io/>
|
||||
|
||||
## Set new repo and pull
|
||||
|
||||
```sh
|
||||
git remote set-url origin https://gitlab.prometheus.systems/firefish/firefish.git
|
||||
git pull --ff
|
||||
```
|
||||
|
||||
In case you get an error like:
|
||||
```
|
||||
error: The following untracked working tree files would be overwritten by merge:
|
||||
packages/backend/assets/LICENSE
|
||||
Please move or remove them before you merge.
|
||||
Aborting
|
||||
```
|
||||
|
||||
Run:
|
||||
```sh
|
||||
rm ./packages/backend/assets/LICENSE
|
||||
git pull --ff
|
||||
```
|
||||
|
||||
## Upgrade packages
|
||||
|
||||
```sh
|
||||
corepack enable
|
||||
pnpm i
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
```sh
|
||||
NODE_ENV=production pnpm run buld
|
||||
```
|
||||
|
||||
## Migrate
|
||||
|
||||
There are 3 new envoriment variables for this upgrade only, because antennas have been moved from the database to the cache.
|
||||
|
||||
- `ANTENNA_MIGRATION_SKIP`: skips copying antennas to cache if `true`. Default is `false` (will clear all antennas if skipped).
|
||||
- `ANTENNA_MIGRATION_COPY_LIMIT`: limits how many entries are copied to cache. Default is `0` (no limit).
|
||||
- `ANTENNA_MIGRATION_READ_LIMIT`: limits how many entires are read from the database
|
||||
in each iteration of migration. Large value may result in faster migration, but also may consume more memory. Default is `10000`.
|
||||
|
||||
With default options:
|
||||
|
||||
```sh
|
||||
NODE_ENV=production pnpm run migrate
|
||||
```
|
||||
|
||||
With custom options (feel free to only use some):
|
||||
|
||||
```sh
|
||||
NODE_ENV=production ANTENNA_MIGRATION_SKIP=false ANTENNA_MIGRATION_COPY_LIMIT=0 ANTENNA_MIGRATION_READ_LIMIT=1000 pnpm run migrate
|
||||
```
|
||||
|
||||
And then restart Calckey...uh... Firefish!
|
16
SECURITY.md
Normal file
16
SECURITY.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Reporting Security Issues
|
||||
|
||||
## Minor Security Issues
|
||||
|
||||
If you discover a minor security issue in Firefish, please report it by sending an
|
||||
email to [kainoa@t1c.dev](mailto:kainoa@t1c.dev).
|
||||
|
||||
## High Security Issues
|
||||
|
||||
If you discover a security issue, which is so high risk, that too much is affected by it, please dont send it over unencrypted communication. You can share your PGP keys with us using kainoa@t1c.dev and after we established a secure communication, send it over E-Mail, or message us using matrix' encrypted private messages at @t1c:matrix.fedibird.com or @cleo:tchncs.de
|
||||
|
||||
|
||||
This will allow us to assess the risk, and make a fix available before we add a
|
||||
bug report to the Gitlab repository.
|
||||
|
||||
Thanks for helping make Firefish safe for everyone.
|
153
animated.svg
Normal file
153
animated.svg
Normal file
|
@ -0,0 +1,153 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1792 1792">
|
||||
|
||||
<style>
|
||||
/* Eyes */
|
||||
@keyframes firefish-logo-blink {
|
||||
95% {
|
||||
transform: scaleY(1);
|
||||
}
|
||||
|
||||
97.5% {
|
||||
transform: scaleY(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
#firefish-logo-eye-l,
|
||||
#firefish-logo-eye-r {
|
||||
transform-origin: center;
|
||||
transform-box: fill-box;
|
||||
animation-name: firefish-logo-blink;
|
||||
animation-duration: 3s;
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
/* Bubbles */
|
||||
@keyframes firefish-logo-bloop {
|
||||
0% {
|
||||
transform: translateY(400px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
20% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
80% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
90% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(-400px);
|
||||
}
|
||||
}
|
||||
|
||||
.firefish-logo-bubble {
|
||||
animation-name: firefish-logo-bloop;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: infinite;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: ease-out;
|
||||
fill: #31748f;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#firefish-logo-bubble-1 {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
#firefish-logo-bubble-2 {
|
||||
animation-delay: .2s;
|
||||
}
|
||||
|
||||
#firefish-logo-bubble-3 {
|
||||
animation-delay: .6s;
|
||||
}
|
||||
|
||||
#firefish-logo-bubble-4 {
|
||||
animation-delay: .8s;
|
||||
}
|
||||
|
||||
#firefish-logo-bubble-5 {
|
||||
animation-delay: 1s;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<linearGradient id="firefish-logo-linear-gradient" x1="26.41" y1="1765.71" x2="1492.49" y2="299.62"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ec476d" />
|
||||
<stop offset="1" stop-color="#f6ae4a" />
|
||||
</linearGradient>
|
||||
<linearGradient id="firefish-logo-linear-gradient-purple" x1="512" y1="1788" x2="512" y2="1398.68"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#db44db" stop-opacity=".3" />
|
||||
<stop offset=".11" stop-color="#db44db" stop-opacity=".21" />
|
||||
<stop offset=".27" stop-color="#db44db" stop-opacity=".12" />
|
||||
<stop offset=".44" stop-color="#db44db" stop-opacity=".05" />
|
||||
<stop offset=".65" stop-color="#db44db" stop-opacity=".01" />
|
||||
<stop offset="1" stop-color="#db44db" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient id="firefish-logo-linear-gradient-3" x1="-351.25" y1="1382.82" x2="1150.74" y2="-119.17"
|
||||
xlink:href="#firefish-logo-linear-gradient" />
|
||||
<linearGradient id="firefish-logo-linear-gradient-4" x1="412.3" y1="2147.8" x2="1915.31" y2="644.8"
|
||||
xlink:href="#firefish-logo-linear-gradient" />
|
||||
<linearGradient id="firefish-logo-linear-gradient-5" x1="28.25" y1="1763.75" x2="1531.25" y2="260.75"
|
||||
xlink:href="#firefish-logo-linear-gradient" />
|
||||
</defs>
|
||||
|
||||
<!-- Bubbles -->
|
||||
<circle id="firefish-logo-bubble-1" class="firefish-logo-bubble" cx="205" cy="500" r="40" />
|
||||
<circle id="firefish-logo-bubble-2" class="firefish-logo-bubble" cx="140" cy="500" r="80" />
|
||||
<circle id="firefish-logo-bubble-3" class="firefish-logo-bubble" cx="95" cy="500" r="70" />
|
||||
<circle id="firefish-logo-bubble-4" class="firefish-logo-bubble" cx="200" cy="500" r="40" />
|
||||
<circle id="firefish-logo-bubble-5" class="firefish-logo-bubble" cx="95" cy="500" r="20" />
|
||||
|
||||
<g id="firefish-logo-firefish">
|
||||
<g id="firefish-logo-fish">
|
||||
<g id="firefish-logo-body">
|
||||
<path
|
||||
d="m928,768.11H96c-53.02,0-96,42.98-96,96v832c0,53.02,42.98,96,96,96h832c53.02,0,96-42.98,96-96v-832c0-53.02-42.98-96-96-96Z"
|
||||
fill="url(#firefish-logo-linear-gradient)" />
|
||||
</g>
|
||||
<g id="firefish-logo-body-purple-grad">
|
||||
<path
|
||||
d="m928,768.11H96C42.98,768.11,0,811.09,0,864.11v832c0,53.02,42.98,96,96,96h832c53.02,0,96-42.98,96-96v-832c0-53.02-42.98-96-96-96Z"
|
||||
fill="url(#firefish-logo-linear-gradient-purple)" />
|
||||
</g>
|
||||
<g id="firefish-logo-fin-l">
|
||||
<path
|
||||
d="m927.66,639.79h-439.94c-52.98,0-95.94-42.95-95.94-95.94V103.91c0-85.47,103.34-128.27,163.77-67.84l439.94,439.94c60.44,60.44,17.63,163.77-67.84,163.77Z"
|
||||
fill="url(#firefish-logo-linear-gradient-3)" />
|
||||
</g>
|
||||
<g id="firefish-logo-fin-b">
|
||||
<path
|
||||
d="m1694.66,1408.11h-445.51c-53.65,0-97.15-43.5-97.15-97.15v-445.51c0-86.55,104.64-129.9,165.84-68.7l445.51,445.51c61.2,61.2,17.86,165.84-68.7,165.84Z"
|
||||
fill="url(#firefish-logo-linear-gradient-4)" />
|
||||
</g>
|
||||
<g id="firefish-logo-fin-r">
|
||||
<path
|
||||
d="m1694.66,640h-445.51c-53.65,0-97.15-43.5-97.15-97.15V97.34c0-86.55,104.64-129.9,165.84-68.7l445.51,445.51c61.2,61.2,17.86,165.84-68.7,165.84Z"
|
||||
fill="url(#firefish-logo-linear-gradient-5)" />
|
||||
</g>
|
||||
<g id="firefish-logo-eye-l">
|
||||
<circle cx="256" cy="1408.11" r="128" fill="#fff" />
|
||||
</g>
|
||||
<g id="firefish-logo-eye-r">
|
||||
<circle cx="576" cy="1408.11" r="128" fill="#fff" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.9 KiB |
13
calckey.apache.conf
Normal file
13
calckey.apache.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Replace example.tld with your domain
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName example.tld
|
||||
# For WebSocket
|
||||
ProxyPass "/streaming" "ws://127.0.0.1:3000/streaming/"
|
||||
# Proxy to Node
|
||||
ProxyPass "/" "http://127.0.0.1:3000/"
|
||||
ProxyPassReverse "/" "http://127.0.0.1:3000/"
|
||||
ProxyPreserveHost On
|
||||
# For files proxy
|
||||
AllowEncodedSlashes On
|
||||
</VirtualHost>
|
23
chart/.helmignore
Normal file
23
chart/.helmignore
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
38
chart/Chart.yaml
Normal file
38
chart/Chart.yaml
Normal file
|
@ -0,0 +1,38 @@
|
|||
apiVersion: v2
|
||||
name: firefish
|
||||
description: A fun, new, open way to experience social media https://joinfirefish.org
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.1.2
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "rc"
|
||||
|
||||
dependencies:
|
||||
- name: elasticsearch
|
||||
version: 19.0.1
|
||||
repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
|
||||
condition: elasticsearch.enabled
|
||||
- name: postgresql
|
||||
version: 11.1.3
|
||||
repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
|
||||
condition: postgresql.enabled
|
||||
- name: redis
|
||||
version: 16.13.2
|
||||
repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
|
||||
condition: redis.enabled
|
89
chart/README.md
Normal file
89
chart/README.md
Normal file
|
@ -0,0 +1,89 @@
|
|||
# firefish
|
||||
|
||||
![Version: 0.1.2](https://img.shields.io/badge/Version-0.1.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: rc](https://img.shields.io/badge/AppVersion-rc-informational?style=flat-square)
|
||||
|
||||
A fun, new, open way to experience social media https://joinfirefish.org
|
||||
|
||||
## Requirements
|
||||
|
||||
| Repository | Name | Version |
|
||||
|------------|------|---------|
|
||||
| https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami | elasticsearch | 19.0.1 |
|
||||
| https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami | postgresql | 11.1.3 |
|
||||
| https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami | redis | 16.13.2 |
|
||||
|
||||
## Values
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| affinity | object | `{}` | |
|
||||
| autoscaling.enabled | bool | `false` | |
|
||||
| autoscaling.maxReplicas | int | `100` | |
|
||||
| autoscaling.minReplicas | int | `1` | |
|
||||
| autoscaling.targetCPUUtilizationPercentage | int | `80` | |
|
||||
| firefish.allowedPrivateNetworks | list | `[]` | If you want to allow firefish to connect to private ips, enter the cidrs here. |
|
||||
| firefish.deepl.authKey | string | `""` | |
|
||||
| firefish.deepl.isPro | bool | `false` | |
|
||||
| firefish.deepl.managed | bool | `false` | |
|
||||
| firefish.domain | string | `"firefish.local"` | |
|
||||
| firefish.isManagedHosting | bool | `true` | |
|
||||
| firefish.libreTranslate.apiKey | string | `""` | |
|
||||
| firefish.libreTranslate.apiUrl | string | `""` | |
|
||||
| firefish.libreTranslate.managed | bool | `false` | |
|
||||
| firefish.objectStorage.access_key | string | `""` | |
|
||||
| firefish.objectStorage.access_secret | string | `""` | |
|
||||
| firefish.objectStorage.baseUrl | string | `""` | |
|
||||
| firefish.objectStorage.bucket | string | `""` | |
|
||||
| firefish.objectStorage.endpoint | string | `""` | |
|
||||
| firefish.objectStorage.managed | bool | `true` | |
|
||||
| firefish.objectStorage.prefix | string | `"files"` | |
|
||||
| firefish.objectStorage.region | string | `""` | |
|
||||
| firefish.reservedUsernames[0] | string | `"root"` | |
|
||||
| firefish.reservedUsernames[1] | string | `"admin"` | |
|
||||
| firefish.reservedUsernames[2] | string | `"administrator"` | |
|
||||
| firefish.reservedUsernames[3] | string | `"me"` | |
|
||||
| firefish.reservedUsernames[4] | string | `"system"` | |
|
||||
| firefish.smtp.from_address | string | `"notifications@example.com"` | |
|
||||
| firefish.smtp.login | string | `""` | |
|
||||
| firefish.smtp.managed | bool | `true` | |
|
||||
| firefish.smtp.password | string | `""` | |
|
||||
| firefish.smtp.port | int | `587` | |
|
||||
| firefish.smtp.server | string | `"smtp.mailgun.org"` | |
|
||||
| firefish.smtp.useImplicitSslTls | bool | `false` | |
|
||||
| elasticsearch | object | `{"auth":{},"enabled":false,"hostname":"","port":9200,"ssl":false}` | https://github.com/bitnami/charts/tree/master/bitnami/elasticsearch#parameters |
|
||||
| fullnameOverride | string | `""` | |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | |
|
||||
| image.repository | string | `"docker.io/thatonecalculator/firefish"` | |
|
||||
| image.tag | string | `""` | |
|
||||
| imagePullSecrets | list | `[]` | |
|
||||
| ingress.annotations | object | `{}` | |
|
||||
| ingress.className | string | `""` | |
|
||||
| ingress.enabled | bool | `false` | |
|
||||
| ingress.hosts[0].host | string | `"chart-example.local"` | |
|
||||
| ingress.hosts[0].paths[0].path | string | `"/"` | |
|
||||
| ingress.hosts[0].paths[0].pathType | string | `"ImplementationSpecific"` | |
|
||||
| ingress.tls | list | `[]` | |
|
||||
| nameOverride | string | `""` | |
|
||||
| nodeSelector | object | `{}` | |
|
||||
| podAnnotations | object | `{}` | |
|
||||
| podSecurityContext | object | `{}` | |
|
||||
| postgresql.auth.database | string | `"firefish_production"` | |
|
||||
| postgresql.auth.password | string | `""` | |
|
||||
| postgresql.auth.username | string | `"firefish"` | |
|
||||
| postgresql.enabled | bool | `true` | disable if you want to use an existing db; in which case the values below must match those of that external postgres instance |
|
||||
| redis.auth.password | string | `""` | you must set a password; the password generated by the redis chart will be rotated on each upgrade: |
|
||||
| redis.enabled | bool | `true` | |
|
||||
| redis.hostname | string | `""` | |
|
||||
| redis.port | int | `6379` | |
|
||||
| replicaCount | int | `1` | |
|
||||
| resources | object | `{}` | |
|
||||
| securityContext | object | `{}` | |
|
||||
| service.port | int | `80` | |
|
||||
| service.type | string | `"ClusterIP"` | |
|
||||
| serviceAccount.annotations | object | `{}` | |
|
||||
| serviceAccount.create | bool | `true` | |
|
||||
| serviceAccount.name | string | `""` | |
|
||||
| tolerations | list | `[]` | |
|
||||
|
||||
----------------------------------------------
|
||||
Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0)
|
22
chart/templates/NOTES.txt
Normal file
22
chart/templates/NOTES.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "firefish.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "firefish.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "firefish.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "firefish.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||
{{- end }}
|
329
chart/templates/_helpers.tpl
Normal file
329
chart/templates/_helpers.tpl
Normal file
|
@ -0,0 +1,329 @@
|
|||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "firefish.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "firefish.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "firefish.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "firefish.labels" -}}
|
||||
helm.sh/chart: {{ include "firefish.chart" . }}
|
||||
{{ include "firefish.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "firefish.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "firefish.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "firefish.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "firefish.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified name for dependent services.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
*/}}
|
||||
{{- define "firefish.elasticsearch.fullname" -}}
|
||||
{{- printf "%s-%s" .Release.Name "elasticsearch" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "firefish.redis.fullname" -}}
|
||||
{{- printf "%s-%s" .Release.Name "redis" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "firefish.postgresql.fullname" -}}
|
||||
{{- printf "%s-%s" .Release.Name "postgresql" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
config/default.yml content
|
||||
*/}}
|
||||
{{- define "firefish.configDir.default.yml" -}}
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# Firefish configuration
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
# ┌─────┐
|
||||
#───┘ URL └─────────────────────────────────────────────────────
|
||||
|
||||
# Final accessible URL seen by a user.
|
||||
url: "https://{{ .Values.firefish.domain }}/"
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# URL SETTINGS AFTER THAT!
|
||||
|
||||
# ┌───────────────────────┐
|
||||
#───┘ Port and TLS settings └───────────────────────────────────
|
||||
|
||||
#
|
||||
# Misskey requires a reverse proxy to support HTTPS connections.
|
||||
#
|
||||
# +----- https://example.tld/ ------------+
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# | User | ---> || Proxy (443) | ---> | Misskey (3000) ||
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# +---------------------------------------+
|
||||
#
|
||||
# You need to set up a reverse proxy. (e.g. nginx)
|
||||
# An encrypted connection with HTTPS is highly recommended
|
||||
# because tokens may be transferred in GET requests.
|
||||
|
||||
# The port that your Misskey server should listen on.
|
||||
port: 3000
|
||||
|
||||
# ┌──────────────────────────┐
|
||||
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||
|
||||
db:
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
host: {{ template "firefish.postgresql.fullname" . }}
|
||||
port: '5432'
|
||||
{{- else }}
|
||||
host: {{ .Values.postgresql.postgresqlHostname }}
|
||||
port: {{ .Values.postgresql.postgresqlPort | default "5432" | quote }}
|
||||
{{- end }}
|
||||
|
||||
# Database name
|
||||
db: {{ .Values.postgresql.auth.database }}
|
||||
|
||||
# Auth
|
||||
user: {{ .Values.postgresql.auth.username }}
|
||||
pass: "{{ .Values.postgresql.auth.password }}"
|
||||
|
||||
# Whether disable Caching queries
|
||||
#disableCache: true
|
||||
|
||||
# Extra Connection options
|
||||
#extra:
|
||||
# ssl:
|
||||
# host: localhost
|
||||
# rejectUnauthorized: false
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Redis configuration └─────────────────────────────────────
|
||||
|
||||
redis:
|
||||
{{- if .Values.redis.enabled }}
|
||||
host: {{ template "firefish.redis.fullname" . }}-master
|
||||
{{- else }}
|
||||
host: {{ required "When the redis chart is disabled .Values.redis.hostname is required" .Values.redis.hostname }}
|
||||
{{- end }}
|
||||
port: {{ .Values.redis.port | default "6379" | quote }}
|
||||
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||
pass: {{ .Values.redis.auth.password | quote }}
|
||||
#prefix: example-prefix
|
||||
#db: 1
|
||||
#user: default
|
||||
#tls:
|
||||
# host: localhost
|
||||
# rejectUnauthorized: false
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Sonic configuration └─────────────────────────────────────
|
||||
|
||||
#sonic:
|
||||
# host: localhost
|
||||
# port: 1491
|
||||
# auth: SecretPassword
|
||||
# collection: notes
|
||||
# bucket: default
|
||||
|
||||
# ┌─────────────────────────────┐
|
||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||
|
||||
{{- if .Values.elasticsearch.enabled }}
|
||||
elasticsearch:
|
||||
host: {{ template "mastodon.elasticsearch.fullname" . }}-master-hl
|
||||
port: 9200
|
||||
ssl: false
|
||||
{{- else if .Values.elasticsearch.hostname }}
|
||||
elasticsearch:
|
||||
host: {{ .Values.elasticsearch.hostname | quote }}
|
||||
port: {{ .Values.elasticsearch.port }}
|
||||
ssl: {{ .Values.elasticsearch.ssl }}
|
||||
{{- if .Values.elasticsearch.auth }}
|
||||
user: {{ .Values.elasticsearch.auth.username | quote }}
|
||||
pass: {{ .Values.elasticsearch.auth.password | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
# ┌───────────────┐
|
||||
#───┘ ID generation └───────────────────────────────────────────
|
||||
|
||||
# You can select the ID generation method.
|
||||
# You don't usually need to change this setting, but you can
|
||||
# change it according to your preferences.
|
||||
|
||||
# Available methods:
|
||||
# aid ... Short, Millisecond accuracy
|
||||
# meid ... Similar to ObjectID, Millisecond accuracy
|
||||
# ulid ... Millisecond accuracy
|
||||
# objectid ... This is left for backward compatibility
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# ID SETTINGS AFTER THAT!
|
||||
|
||||
id: 'aid'
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Other configuration └─────────────────────────────────────
|
||||
|
||||
# Max note length, should be < 8000.
|
||||
#maxNoteLength: 3000
|
||||
|
||||
# Maximum lenght of an image caption or file comment (default 1500, max 8192)
|
||||
#maxCaptionLength: 1500
|
||||
|
||||
# Reserved usernames that only the administrator can register with
|
||||
reservedUsernames:
|
||||
{{ .Values.firefish.reservedUsernames | toYaml }}
|
||||
|
||||
# Whether disable HSTS
|
||||
#disableHsts: true
|
||||
|
||||
# Number of worker processes
|
||||
#clusterLimit: 1
|
||||
|
||||
# Job concurrency per worker
|
||||
# deliverJobConcurrency: 128
|
||||
# inboxJobConcurrency: 16
|
||||
|
||||
# Job rate limiter
|
||||
# deliverJobPerSec: 128
|
||||
# inboxJobPerSec: 16
|
||||
|
||||
# Job attempts
|
||||
# deliverJobMaxAttempts: 12
|
||||
# inboxJobMaxAttempts: 8
|
||||
|
||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||
#outgoingAddressFamily: ipv4
|
||||
|
||||
# Syslog option
|
||||
#syslog:
|
||||
# host: localhost
|
||||
# port: 514
|
||||
|
||||
# Proxy for HTTP/HTTPS
|
||||
#proxy: http://127.0.0.1:3128
|
||||
|
||||
#proxyBypassHosts: [
|
||||
# 'example.com',
|
||||
# '192.0.2.8'
|
||||
#]
|
||||
|
||||
# Proxy for SMTP/SMTPS
|
||||
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
|
||||
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
|
||||
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
|
||||
|
||||
# Media Proxy
|
||||
#mediaProxy: https://example.com/proxy
|
||||
|
||||
# Proxy remote files (default: false)
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
allowedPrivateNetworks:
|
||||
{{ .Values.firefish.allowedPrivateNetworks | toYaml }}
|
||||
|
||||
# TWA
|
||||
#twa:
|
||||
# nameSpace: android_app
|
||||
# packageName: tld.domain.twa
|
||||
# sha256CertFingerprints: ['AB:CD:EF']
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
||||
|
||||
# Managed hosting settings
|
||||
# !!!!!!!!!!
|
||||
# >>>>>> NORMAL SELF-HOSTERS, STAY AWAY! <<<<<<
|
||||
# >>>>>> YOU DON'T NEED THIS! <<<<<<
|
||||
# !!!!!!!!!!
|
||||
# Each category is optional, but if each item in each category is mandatory!
|
||||
# If you mess this up, that's on you, you've been warned...
|
||||
|
||||
#maxUserSignups: 100
|
||||
isManagedHosting: {{ .Values.firefish.isManagedHosting }}
|
||||
deepl:
|
||||
managed: {{ .Values.firefish.deepl.managed }}
|
||||
authKey: {{ .Values.firefish.deepl.authKey | quote}}
|
||||
isPro: {{ .Values.firefish.deepl.isPro }}
|
||||
|
||||
libreTranslate:
|
||||
managed: {{ .Values.firefish.libreTranslate.managed }}
|
||||
apiUrl: {{ .Values.firefish.libreTranslate.apiUrl | quote }}
|
||||
apiKey: {{ .Values.firefish.libreTranslate.apiKey | quote }}
|
||||
|
||||
email:
|
||||
managed: {{ .Values.firefish.smtp.managed }}
|
||||
address: {{ .Values.firefish.smtp.from_address | quote }}
|
||||
host: {{ .Values.firefish.smtp.server | quote }}
|
||||
port: {{ .Values.firefish.smtp.port }}
|
||||
user: {{ .Values.firefish.smtp.login | quote }}
|
||||
pass: {{ .Values.firefish.smtp.password | quote }}
|
||||
useImplicitSslTls: {{ .Values.firefish.smtp.useImplicitSslTls }}
|
||||
objectStorage:
|
||||
managed: {{ .Values.firefish.objectStorage.managed }}
|
||||
baseUrl: {{ .Values.firefish.objectStorage.baseUrl | quote }}
|
||||
bucket: {{ .Values.firefish.objectStorage.bucket | quote }}
|
||||
prefix: {{ .Values.firefish.objectStorage.prefix | quote }}
|
||||
endpoint: {{ .Values.firefish.objectStorage.endpoint | quote }}
|
||||
region: {{ .Values.firefish.objectStorage.region | quote }}
|
||||
accessKey: {{ .Values.firefish.objectStorage.access_key | quote }}
|
||||
secretKey: {{ .Values.firefish.objectStorage.access_secret | quote }}
|
||||
useSsl: true
|
||||
connnectOverProxy: false
|
||||
setPublicReadOnUpload: true
|
||||
s3ForcePathStyle: true
|
||||
|
||||
# !!!!!!!!!!
|
||||
# >>>>>> AGAIN, NORMAL SELF-HOSTERS, STAY AWAY! <<<<<<
|
||||
# >>>>>> YOU DON'T NEED THIS, ABOVE SETTINGS ARE FOR MANAGED HOSTING ONLY! <<<<<<
|
||||
# !!!!!!!!!!
|
||||
|
||||
# Seriously. Do NOT fill out the above settings if you're self-hosting.
|
||||
# They're much better off being set from the control panel.
|
||||
{{- end }}
|
82
chart/templates/deployment.yaml
Normal file
82
chart/templates/deployment.yaml
Normal file
|
@ -0,0 +1,82 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "firefish.fullname" . }}
|
||||
labels:
|
||||
{{- include "firefish.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "firefish.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/secret-config: {{ include ( print $.Template.BasePath "/secret-config.yaml" ) . | sha256sum | quote }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "firefish.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "firefish.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
volumes:
|
||||
- name: config-volume
|
||||
secret:
|
||||
secretName: {{ template "firefish.fullname" . }}-config
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command:
|
||||
- pnpm
|
||||
- run
|
||||
- start
|
||||
env:
|
||||
- name: "NODE_ENV"
|
||||
value: "production"
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /firefish/.config
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 3000
|
||||
protocol: TCP
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
failureThreshold: 30
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
28
chart/templates/hpa.yaml
Normal file
28
chart/templates/hpa.yaml
Normal file
|
@ -0,0 +1,28 @@
|
|||
{{- if .Values.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "firefish.fullname" . }}
|
||||
labels:
|
||||
{{- include "firefish.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "firefish.fullname" . }}
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
61
chart/templates/ingress.yaml
Normal file
61
chart/templates/ingress.yaml
Normal file
|
@ -0,0 +1,61 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "firefish.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
||||
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
|
||||
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "firefish.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
|
||||
pathType: {{ .pathType }}
|
||||
{{- end }}
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ $fullName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- else }}
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
59
chart/templates/job-db-migrate.yaml
Normal file
59
chart/templates/job-db-migrate.yaml
Normal file
|
@ -0,0 +1,59 @@
|
|||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ include "firefish.fullname" . }}-db-migrate
|
||||
labels:
|
||||
{{- include "firefish.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,pre-upgrade
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
"helm.sh/hook-weight": "-2"
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
name: {{ include "firefish.fullname" . }}-db-migrate
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "firefish.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
volumes:
|
||||
- name: config-volume
|
||||
secret:
|
||||
secretName: {{ template "firefish.fullname" . }}-config
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command:
|
||||
- pnpm
|
||||
- run
|
||||
- migrate
|
||||
env:
|
||||
- name: "NODE_ENV"
|
||||
value: "production"
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /firefish/.config
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
9
chart/templates/secret-config.yaml
Normal file
9
chart/templates/secret-config.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "firefish.fullname" . }}-config
|
||||
labels:
|
||||
{{- include "firefish.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
default.yml: {{ include "firefish.configDir.default.yml" . | b64enc }}
|
15
chart/templates/service.yaml
Normal file
15
chart/templates/service.yaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "firefish.fullname" . }}
|
||||
labels:
|
||||
{{- include "firefish.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "firefish.selectorLabels" . | nindent 4 }}
|
12
chart/templates/serviceaccount.yaml
Normal file
12
chart/templates/serviceaccount.yaml
Normal file
|
@ -0,0 +1,12 @@
|
|||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "firefish.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "firefish.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
15
chart/templates/tests/test-connection.yaml
Normal file
15
chart/templates/tests/test-connection.yaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "firefish.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{- include "firefish.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "firefish.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
168
chart/values.yaml
Normal file
168
chart/values.yaml
Normal file
|
@ -0,0 +1,168 @@
|
|||
# Default values for firefish.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: docker.io/thatonecalculator/firefish
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
firefish:
|
||||
isManagedHosting: true
|
||||
domain: firefish.local
|
||||
|
||||
deepl:
|
||||
managed: false
|
||||
authKey: ""
|
||||
isPro: false
|
||||
|
||||
libreTranslate:
|
||||
managed: false
|
||||
apiUrl: ""
|
||||
apiKey: ""
|
||||
|
||||
smtp:
|
||||
managed: true
|
||||
from_address: notifications@example.com
|
||||
port: 587
|
||||
server: smtp.mailgun.org
|
||||
useImplicitSslTls: false
|
||||
login: ""
|
||||
password: ""
|
||||
|
||||
objectStorage:
|
||||
managed: true
|
||||
access_key: ""
|
||||
access_secret: ""
|
||||
baseUrl: "" # e.g. "https://my-bucket.nyc3.cdn.digitaloceanspaces.com"
|
||||
bucket: "" # e.g. "my-bucket"
|
||||
prefix: files
|
||||
endpoint: "" # e.g. "nyc3.digitaloceanspaces.com:443"
|
||||
region: "" # e.g. "nyc3"
|
||||
|
||||
# -- If you want to allow firefish to connect to private ips, enter the cidrs here.
|
||||
allowedPrivateNetworks: []
|
||||
# - "10.0.0.0/8"
|
||||
|
||||
reservedUsernames:
|
||||
- root
|
||||
- admin
|
||||
- administrator
|
||||
- me
|
||||
- system
|
||||
|
||||
# https://github.com/bitnami/charts/tree/master/bitnami/postgresql#parameters
|
||||
postgresql:
|
||||
# -- disable if you want to use an existing db; in which case the values below
|
||||
# must match those of that external postgres instance
|
||||
enabled: true
|
||||
# postgresqlHostname: preexisting-postgresql
|
||||
# postgresqlPort: 5432
|
||||
auth:
|
||||
database: firefish_production
|
||||
username: firefish
|
||||
# you must set a password; the password generated by the postgresql chart will
|
||||
# be rotated on each upgrade:
|
||||
# https://github.com/bitnami/charts/tree/master/bitnami/postgresql#upgrade
|
||||
password: ""
|
||||
|
||||
# https://github.com/bitnami/charts/tree/master/bitnami/redis#parameters
|
||||
redis:
|
||||
# disable if you want to use an existing redis instance; in which case the
|
||||
# values below must match those of that external redis instance
|
||||
enabled: true
|
||||
hostname: ""
|
||||
port: 6379
|
||||
auth:
|
||||
# -- you must set a password; the password generated by the redis chart will be
|
||||
# rotated on each upgrade:
|
||||
password: ""
|
||||
|
||||
# -- https://github.com/bitnami/charts/tree/master/bitnami/elasticsearch#parameters
|
||||
elasticsearch:
|
||||
# disable if you want to use an existing redis instance; in which case the
|
||||
# values below must match those of that external elasticsearch instance
|
||||
enabled: false
|
||||
hostname: ""
|
||||
port: 9200
|
||||
ssl: false
|
||||
auth: {}
|
||||
# username: ""
|
||||
# password: ""
|
||||
# @ignored
|
||||
image:
|
||||
tag: 7
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: chart-example.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 100
|
||||
targetCPUUtilizationPercentage: 80
|
||||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
99
cliff.toml
Normal file
99
cliff.toml
Normal file
|
@ -0,0 +1,99 @@
|
|||
# configuration file for git-cliff (0.1.0)
|
||||
|
||||
[changelog]
|
||||
# changelog header
|
||||
header = """
|
||||
# Changelog\n
|
||||
All changes from v13.0.0 onwards, for a list of differences read FIREFISH.md\n
|
||||
"""
|
||||
# template for the changelog body
|
||||
# https://tera.netlify.app/docs/#introduction
|
||||
body = """
|
||||
{% if version %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{% else %}\
|
||||
## [unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
### {{ group | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
|
||||
{% endfor %}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
# remove the leading and trailing whitespace from the template
|
||||
trim = true
|
||||
# changelog footer
|
||||
footer = """
|
||||
<!-- generated by git-cliff -->
|
||||
"""
|
||||
|
||||
[git]
|
||||
# parse the commits based on https://www.conventionalcommits.org
|
||||
conventional_commits = false
|
||||
# filter out the commits that are not conventional
|
||||
filter_unconventional = true
|
||||
# process each line of a commit as an individual commit
|
||||
split_commits = false
|
||||
# regex for parsing and grouping commits
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "Features"},
|
||||
{ message = "^add", group = "Features"},
|
||||
{ message = "^fix", group = "Bug Fixes"},
|
||||
{ message = "^prevent", group = "Bug Fixes"},
|
||||
{ message = "^doc", group = "Documentation"},
|
||||
{ message = "^perf", group = "Performance"},
|
||||
{ message = "^🎨", group = "Refactor"},
|
||||
{ message = "^enhance", group = "Refactor"},
|
||||
{ message = "^⚡️", group = "Refactor"},
|
||||
{ message = "^🔥", group = "Features"},
|
||||
{ message = "^🐛", group = "Bug Fixes"},
|
||||
{ message = "^🚑️", group = "Bug Fixes"},
|
||||
{ message = "^block", group = "Bug Fixes"},
|
||||
{ message = "^✨", group = "Features"},
|
||||
{ message = "^📝", group = "Documentation"},
|
||||
{ message = "^🚀", group = "Features"},
|
||||
{ message = "^💄", group = "Styling"},
|
||||
{ message = "^✅", group = "Testing"},
|
||||
{ message = "^🔒️", group = "Security"},
|
||||
{ message = "^🚨", group = "Testing"},
|
||||
{ message = "^💚", group = "CI"},
|
||||
{ message = "^👷", group = "CI"},
|
||||
{ message = "^⬇️", group = "Miscellaneous Tasks"},
|
||||
{ message = "^⬆️", group = "Miscellaneous Tasks"},
|
||||
{ message = "^📌", group = "Miscellaneous Tasks"},
|
||||
{ message = "^➕", group = "Miscellaneous Tasks"},
|
||||
{ message = "^➖", group = "Miscellaneous Tasks"},
|
||||
{ message = "^♻️", group = "Refactor"},
|
||||
{ message = "^🔧", group = "CI"},
|
||||
{ message = "^🔨", group = "CI"},
|
||||
{ message = "^🌐", group = "Localization"},
|
||||
{ message = "^✏️", group = "Localization"},
|
||||
{ message = "^👽️", group = "Bug Fixes"},
|
||||
{ message = "^🍱", group = "Styling"},
|
||||
{ message = "^♿️", group = "Styling"},
|
||||
{ message = "^🩹", group = "Bug Fixes"},
|
||||
{ message = "^refactor", group = "Refactor"},
|
||||
{ message = "^style", group = "Styling"},
|
||||
{ message = "^test", group = "Testing"},
|
||||
{ message = "^chore\\(release\\): prepare for", skip = true},
|
||||
{ message = "^chore", group = "Miscellaneous Tasks"},
|
||||
{ message = "^update", group = "Miscellaneous Tasks"},
|
||||
{ body = ".*security", group = "Security"},
|
||||
]
|
||||
# protect breaking changes from being skipped due to matching a skipping commit_parser
|
||||
protect_breaking_commits = false
|
||||
# filter out the commits that are not matched by commit parsers
|
||||
filter_commits = false
|
||||
# glob pattern for matching git tags
|
||||
tag_pattern = "v[0-9]*"
|
||||
# regex for skipping tags
|
||||
skip_tags = "v0.1.0-beta.1"
|
||||
# regex for ignoring tags
|
||||
ignore_tags = ""
|
||||
# sort the tags chronologically
|
||||
date_order = false
|
||||
# sort the commits inside sections by oldest/newest order
|
||||
sort_commits = "oldest"
|
||||
# limit the number of commits included in the changelog.
|
||||
# limit_commits = 42
|
13
custom/assets/LICENSE
Normal file
13
custom/assets/LICENSE
Normal file
|
@ -0,0 +1,13 @@
|
|||
Copyright 2023 Firefish
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
custom/assets/badges/error.png
Normal file
BIN
custom/assets/badges/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
custom/assets/badges/info.png
Normal file
BIN
custom/assets/badges/info.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
BIN
custom/assets/badges/not-found.png
Normal file
BIN
custom/assets/badges/not-found.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
7
custom/assets/instance.css
Normal file
7
custom/assets/instance.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* !!! WARNING !!!
|
||||
* Editing this file may cause your instance to break for EVERYONE.
|
||||
* Please know what you're doing and test it out with regular user custom CSS.
|
||||
* With that said, GLHF!
|
||||
* This may eventuallly be replaced with a function in the admin panel.
|
||||
*/
|
0
custom/locales/.gitkeep
Normal file
0
custom/locales/.gitkeep
Normal file
12
cypress.config.ts
Normal file
12
cypress.config.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require("./cypress/plugins/index.js")(on, config);
|
||||
},
|
||||
baseUrl: "http://localhost:61812",
|
||||
},
|
||||
});
|
151
cypress/e2e/basic.cy.js
Normal file
151
cypress/e2e/basic.cy.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
describe("Before setup instance", () => {
|
||||
beforeEach(() => {
|
||||
cy.resetState();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
|
||||
// waitを入れることでそれを防止できる
|
||||
cy.wait(1000);
|
||||
});
|
||||
|
||||
it("successfully loads", () => {
|
||||
cy.visit("/");
|
||||
});
|
||||
|
||||
it("setup instance", () => {
|
||||
cy.visit("/");
|
||||
|
||||
cy.intercept("POST", "/api/admin/accounts/create").as("signup");
|
||||
|
||||
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();
|
||||
|
||||
// なぜか動かない
|
||||
//cy.wait('@signup').should('have.property', 'response.statusCode');
|
||||
cy.wait("@signup");
|
||||
});
|
||||
});
|
||||
|
||||
describe("After setup instance", () => {
|
||||
beforeEach(() => {
|
||||
cy.resetState();
|
||||
|
||||
// インスタンス初期セットアップ
|
||||
cy.registerUser("admin", "pass", true);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
|
||||
// waitを入れることでそれを防止できる
|
||||
cy.wait(1000);
|
||||
});
|
||||
|
||||
it("successfully loads", () => {
|
||||
cy.visit("/");
|
||||
});
|
||||
|
||||
it("signup", () => {
|
||||
cy.visit("/");
|
||||
|
||||
cy.intercept("POST", "/api/signup").as("signup");
|
||||
|
||||
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();
|
||||
|
||||
cy.wait("@signup");
|
||||
});
|
||||
});
|
||||
|
||||
describe("After user signup", () => {
|
||||
beforeEach(() => {
|
||||
cy.resetState();
|
||||
|
||||
// インスタンス初期セットアップ
|
||||
cy.registerUser("admin", "pass", true);
|
||||
|
||||
// ユーザー作成
|
||||
cy.registerUser("alice", "alice1234");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
|
||||
// waitを入れることでそれを防止できる
|
||||
cy.wait(1000);
|
||||
});
|
||||
|
||||
it("successfully loads", () => {
|
||||
cy.visit("/");
|
||||
});
|
||||
|
||||
it("signin", () => {
|
||||
cy.visit("/");
|
||||
|
||||
cy.intercept("POST", "/api/signin").as("signin");
|
||||
|
||||
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}");
|
||||
|
||||
cy.wait("@signin");
|
||||
});
|
||||
|
||||
it("suspend", function () {
|
||||
cy.request("POST", "/api/admin/suspend-user", {
|
||||
i: this.admin.token,
|
||||
userId: this.alice.id,
|
||||
});
|
||||
|
||||
cy.visit("/");
|
||||
|
||||
cy.get("[data-cy-signin]").click();
|
||||
cy.get("[data-cy-signin-username] input").type("alice");
|
||||
cy.get("[data-cy-signin-password] input").type("alice1234{enter}");
|
||||
|
||||
// TODO: cypressにブラウザの言語指定できる機能が実装され次第英語のみテストするようにする
|
||||
cy.contains(
|
||||
/アカウントが凍結されています|This account has been suspended due to/gi,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("After user singed in", () => {
|
||||
beforeEach(() => {
|
||||
cy.resetState();
|
||||
|
||||
// インスタンス初期セットアップ
|
||||
cy.registerUser("admin", "pass", true);
|
||||
|
||||
// ユーザー作成
|
||||
cy.registerUser("alice", "alice1234");
|
||||
|
||||
cy.login("alice", "alice1234");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
|
||||
// waitを入れることでそれを防止できる
|
||||
cy.wait(1000);
|
||||
});
|
||||
|
||||
it("successfully loads", () => {
|
||||
cy.get("[data-cy-open-post-form]").should("be.visible");
|
||||
});
|
||||
|
||||
it("note", () => {
|
||||
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();
|
||||
|
||||
cy.contains("Hello, Misskey!");
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: 投稿フォームの公開範囲指定のテスト
|
||||
// TODO: 投稿フォームのファイル添付のテスト
|
||||
// TODO: 投稿フォームのハッシュタグ保持フィールドのテスト
|
63
cypress/e2e/widgets.cy.js
Normal file
63
cypress/e2e/widgets.cy.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
describe("After user signed in", () => {
|
||||
beforeEach(() => {
|
||||
cy.resetState();
|
||||
cy.viewport("macbook-16");
|
||||
// インスタンス初期セットアップ
|
||||
cy.registerUser("admin", "pass", true);
|
||||
|
||||
// ユーザー作成
|
||||
cy.registerUser("alice", "alice1234");
|
||||
|
||||
cy.login("alice", "alice1234");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
|
||||
// waitを入れることでそれを防止できる
|
||||
cy.wait(1000);
|
||||
});
|
||||
|
||||
it("widget edit toggle is visible", () => {
|
||||
cy.get(".mk-widget-edit").should("be.visible");
|
||||
});
|
||||
|
||||
it("widget select should be visible in edit mode", () => {
|
||||
cy.get(".mk-widget-edit").click();
|
||||
cy.get(".mk-widget-select").should("be.visible");
|
||||
});
|
||||
|
||||
it("first widget should be removed", () => {
|
||||
cy.get(".mk-widget-edit").click();
|
||||
cy.get(".customize-container:first-child .remove._button").click();
|
||||
cy.get(".customize-container").should("have.length", 2);
|
||||
});
|
||||
|
||||
function buildWidgetTest(widgetName) {
|
||||
it(`${widgetName} widget should get added`, () => {
|
||||
cy.get(".mk-widget-edit").click();
|
||||
cy.get(".mk-widget-select select").select(widgetName, { force: true });
|
||||
cy.get(".bg._modalBg.transparent").click({ multiple: true, force: true });
|
||||
cy.get(".mk-widget-add").click({ force: true });
|
||||
cy.get(`.mkw-${widgetName}`).should("exist");
|
||||
});
|
||||
}
|
||||
|
||||
buildWidgetTest("memo");
|
||||
buildWidgetTest("notifications");
|
||||
buildWidgetTest("timeline");
|
||||
buildWidgetTest("calendar");
|
||||
buildWidgetTest("rss");
|
||||
buildWidgetTest("trends");
|
||||
buildWidgetTest("clock");
|
||||
buildWidgetTest("activity");
|
||||
buildWidgetTest("photos");
|
||||
buildWidgetTest("digitalClock");
|
||||
buildWidgetTest("federation");
|
||||
buildWidgetTest("postForm");
|
||||
buildWidgetTest("slideshow");
|
||||
buildWidgetTest("serverMetric");
|
||||
buildWidgetTest("onlineUsers");
|
||||
buildWidgetTest("jobQueue");
|
||||
buildWidgetTest("button");
|
||||
buildWidgetTest("aiscript");
|
||||
});
|
5
cypress/fixtures/example.json
Normal file
5
cypress/fixtures/example.json
Normal 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"
|
||||
}
|
21
cypress/plugins/index.js
Normal file
21
cypress/plugins/index.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
/// <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}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
};
|
57
cypress/support/commands.js
Normal file
57
cypress/support/commands.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
// ***********************************************
|
||||
// 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) => { ... })
|
||||
|
||||
Cypress.Commands.add("resetState", () => {
|
||||
cy.window((win) => {
|
||||
win.indexedDB.deleteDatabase("keyval-store");
|
||||
});
|
||||
cy.request("POST", "/api/reset-db").as("reset");
|
||||
cy.get("@reset").its("status").should("equal", 204);
|
||||
cy.reload(true);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("registerUser", (username, password, isAdmin = false) => {
|
||||
const route = isAdmin ? "/api/admin/accounts/create" : "/api/signup";
|
||||
|
||||
cy.request("POST", route, {
|
||||
username: username,
|
||||
password: password,
|
||||
})
|
||||
.its("body")
|
||||
.as(username);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("login", (username, password) => {
|
||||
cy.visit("/");
|
||||
|
||||
cy.intercept("POST", "/api/signin").as("signin");
|
||||
|
||||
cy.get("[data-cy-signin]").click();
|
||||
cy.get("[data-cy-signin-username] input").type(username);
|
||||
cy.get("[data-cy-signin-password] input").type(`${password}{enter}`);
|
||||
|
||||
cy.wait("@signin").as("signedIn");
|
||||
});
|
34
cypress/support/e2e.js
Normal file
34
cypress/support/e2e.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
// ***********************************************************
|
||||
// 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')
|
||||
|
||||
Cypress.on("uncaught:exception", (err, runnable) => {
|
||||
if (
|
||||
[
|
||||
// Chrome
|
||||
"ResizeObserver loop limit exceeded",
|
||||
|
||||
// Firefox
|
||||
"ResizeObserver loop completed with undelivered notifications",
|
||||
].some((msg) => err.message.includes(msg))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
});
|
57
dev/docker-compose.yml.example
Normal file
57
dev/docker-compose.yml.example
Normal file
|
@ -0,0 +1,57 @@
|
|||
version: "3"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: docker.io/thatonecalculator/firefish
|
||||
build: ..
|
||||
container_name: firefish_web
|
||||
restart: always
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
# - es
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
- network
|
||||
# - web
|
||||
volumes:
|
||||
- ../files:/firefish/files
|
||||
- ../.config:/firefish/.config:ro
|
||||
|
||||
redis:
|
||||
restart: always
|
||||
container_name: firefish_redis
|
||||
image: docker.io/redis:7.0-alpine
|
||||
networks:
|
||||
- network
|
||||
volumes:
|
||||
- ../redis:/data
|
||||
|
||||
db:
|
||||
restart: always
|
||||
image: docker.io/postgres:12.2-alpine
|
||||
container_name: firefish_db
|
||||
networks:
|
||||
- network
|
||||
env_file:
|
||||
- ../.config/docker.env
|
||||
volumes:
|
||||
- ../db:/var/lib/postgresql/data
|
||||
|
||||
# es:
|
||||
# restart: always
|
||||
# image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.2
|
||||
# environment:
|
||||
# - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
|
||||
# - "TAKE_FILE_OWNERSHIP=111"
|
||||
# networks:
|
||||
# - network
|
||||
# volumes:
|
||||
# - ./elasticsearch:/usr/share/elasticsearch/data
|
||||
|
||||
networks:
|
||||
network:
|
||||
# web:
|
||||
# external:
|
||||
# name: web
|
74
docker-compose.yml
Normal file
74
docker-compose.yml
Normal file
|
@ -0,0 +1,74 @@
|
|||
version: "3"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: docker.io/thatonecalculator/firefish
|
||||
container_name: firefish_web
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
### Uncomment one of the following to use a search engine
|
||||
# - meilisearch
|
||||
# - sonic
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
- calcnet
|
||||
# - web
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
volumes:
|
||||
- ./files:/firefish/files
|
||||
- ./.config:/firefish/.config:ro
|
||||
|
||||
redis:
|
||||
restart: unless-stopped
|
||||
image: docker.io/redis:7.0-alpine
|
||||
container_name: firefish_redis
|
||||
networks:
|
||||
- calcnet
|
||||
volumes:
|
||||
- ./redis:/data
|
||||
|
||||
db:
|
||||
restart: unless-stopped
|
||||
image: docker.io/postgres:12.2-alpine
|
||||
container_name: firefish_db
|
||||
networks:
|
||||
- calcnet
|
||||
env_file:
|
||||
- .config/docker.env
|
||||
volumes:
|
||||
- ./db:/var/lib/postgresql/data
|
||||
|
||||
### Only one of the below should be used.
|
||||
### Meilisearch is better overall, but resource-intensive. Sonic is a very light full text search engine.
|
||||
|
||||
# meilisearch:
|
||||
# container_name: meilisearch
|
||||
# image: getmeili/meilisearch:v1.1.1
|
||||
# environment:
|
||||
# - MEILI_ENV=${MEILI_ENV:-development}
|
||||
# ports:
|
||||
# - "7700:7700"
|
||||
# networks:
|
||||
# - calcnet
|
||||
# volumes:
|
||||
# - ./meili_data:/meili_data
|
||||
# restart: unless-stopped
|
||||
|
||||
# sonic:
|
||||
# restart: unless-stopped
|
||||
# image: docker.io/valeriansaliou/sonic:v1.4.0
|
||||
# networks:
|
||||
# - calcnet
|
||||
# volumes:
|
||||
# - ./sonic:/var/lib/sonic/store
|
||||
# - ./sonic/config.cfg:/etc/sonic.cfg
|
||||
|
||||
networks:
|
||||
calcnet:
|
||||
# web:
|
||||
# external:
|
||||
# name: web
|
5
docs/api-doc.md
Normal file
5
docs/api-doc.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# API Documentation
|
||||
|
||||
You can find interactive API documentation at any Firefish instance. https://firefish.social/api-doc
|
||||
|
||||
You can also find auto-generated documentation for firefish-js [here](../packages/firefish-js/markdown/firefish-js.md).
|
108
docs/development.md
Normal file
108
docs/development.md
Normal file
|
@ -0,0 +1,108 @@
|
|||
# 🌎 Firefish Developer Docs
|
||||
|
||||
## Nix Dev Environment
|
||||
The Firefish repo comes with a Nix-based shell environment to help make development as easy as possible!
|
||||
|
||||
Please note, however, that this environment will not work on Windows outside of a WSL2 environment.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Installed the [Nix Package Manager](https://nixos.org/download.html) (use the comman on their website)
|
||||
- Installed [direnv](https://direnv.net/docs/installation.html) and added its hook to your shell. (package manager)
|
||||
|
||||
Once the repo is cloned to your computer, follow these next few steps inside the Firefish folder:
|
||||
|
||||
- Run `direnv allow`. This will build the environment and install all needed tools.
|
||||
- Run `install-deps`, then `prepare-config`, to install the node dependencies and prepare the needed config files.
|
||||
- In a second terminal, run `devenv up`. This will spawn a **Redis** server, a **Postgres** server, and the **Firefish** server in dev mode.
|
||||
- Once you see the Firefish banner printed in your second terminal, run `migrate` in the first.
|
||||
- Once migrations finish, open http://localhost:3000 in your web browser.
|
||||
- You should now see the admin user creation screen!
|
||||
|
||||
Note: When you want to restart a dev server, all you need to do is run `devenv up`, no other steps are necessary.
|
||||
|
||||
# Possible Troubles with the dev enviroment
|
||||
(this doesn't have to be done under normal conditions, this is for future reference)
|
||||
|
||||
### direnv
|
||||
If you have any trouble with `direnv allow`
|
||||
Check that the contents of `.envrc` have the same version of nix-direnv that is specified here:
|
||||
> nix-direnv under -> installation -> using direnv source url
|
||||
> https://github.com/nix-community/nix-direnv#direnv-source_url
|
||||
|
||||
there should be no errors during `direnv allow`
|
||||
|
||||
### outdated nix packages
|
||||
if `install-deps` or any subsequent command doesn't run due to versioning problems
|
||||
`flake.nix` and `flake.lock` may be outdated
|
||||
|
||||
delete `flake.lock`, or better, run `nix flake update --extra-experimental-features flakes --extra-experimental-features nix-command`
|
||||
after that, run `direnv rebuild`
|
||||
|
||||
if there are any errors, you might have to change `flake.nix`
|
||||
(because the available options can change between versions - consider getting support in [the matrix channel](https://matrix.to/#/#firefish:matrix.fedibird.com))
|
||||
|
||||
### after changing a node version
|
||||
in my case, i had to change the node version from 19, to 18
|
||||
|
||||
! before proceeding, make sure to delete all build artifacts!
|
||||
remove `node_modules` and `built` folders, and maybe `.devenv` and `.direnv` as well
|
||||
manually, or run `npm cache clean --force` and `pnpm cleanall`
|
||||
|
||||
### Windows Subsystem for Linux
|
||||
if `devenv up` terminates because of wrong folder permissions,
|
||||
|
||||
create the file `/etc/wsl.conf` in your distro and add
|
||||
```shell
|
||||
[automount]
|
||||
options = "metadata"
|
||||
```
|
||||
|
||||
this allows `chmod` calls to actually have an effect.
|
||||
the build scripts DO actually set the permissions, it just needs to work in wsl.
|
||||
|
||||
### devenv up
|
||||
devenv up may take a looong time. (some say this is fake news, maybe it was bad luck in my case)
|
||||
|
||||
do not get spooked by this error:
|
||||
```
|
||||
> firefish@14.0.0-dev32 start /mnt/.../firefish
|
||||
> pnpm --filter backend run start
|
||||
|
||||
|
||||
> backend@ start /mnt/.../firefish/packages/backend
|
||||
> pnpm node ./built/index.js
|
||||
|
||||
node:internal/modules/cjs/loader:1078
|
||||
throw err;
|
||||
^
|
||||
|
||||
Error: Cannot find module '/mnt/.../firefish/packages/backend/built/index.js'
|
||||
at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15)
|
||||
at Module._load (node:internal/modules/cjs/loader:920:27)
|
||||
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
|
||||
at node:internal/main/run_main_module:23:47 {
|
||||
code: 'MODULE_NOT_FOUND',
|
||||
requireStack: []
|
||||
}
|
||||
|
||||
Node.js v18.16.0
|
||||
undefined
|
||||
/mnt/.../firefish/packages/backend:
|
||||
ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL backend@ start: `pnpm node ./built/index.js`
|
||||
Exit status 1
|
||||
ELIFECYCLE Command failed with exit code 1.
|
||||
```
|
||||
|
||||
the script is designed to constantly try to start the server, while the build is still running.
|
||||
this just means that the build isn't finished yet.
|
||||
|
||||
at some point you should see a banner that says "Firefish" in big letters -
|
||||
then you're good to go and can run `migrate` (in another terminal)!
|
||||
|
||||
if you don't see the banner,
|
||||
and it's for some reason stuck on `Finished 'build' after 917 ms` for a view minutes,
|
||||
|
||||
just leave devenv running and open another terminal in the folder
|
||||
run `migrate` and then `pnpm --filter backend run start` by yourself
|
||||
the server should start
|
48
docs/docker.md
Normal file
48
docs/docker.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
# 🐳 Running a Firefish server with Docker
|
||||
|
||||
## Pre-built docker container
|
||||
[thatonecalculator/firefish](https://hub.docker.com/r/thatonecalculator/firefish)
|
||||
|
||||
## `docker-compose`
|
||||
|
||||
There is a `docker-compose.yml` in the root of the project that you can use to build the container from source
|
||||
|
||||
- .config/docker.env (**db config settings**)
|
||||
- .config/default.yml (**firefish server settings**)
|
||||
|
||||
## Configuring
|
||||
|
||||
Rename the files:
|
||||
|
||||
`cp .config/example.yml .config/default.yml`
|
||||
|
||||
`cp .config/example.env .config/docker.env`
|
||||
|
||||
then edit them according to your environment.
|
||||
You can configure `docker.env` with anything you like, but you will have to pay attention to the `default.yml` file:
|
||||
- `url` should be set to the URL you will be hosting the web interface for the server at.
|
||||
- `host`, `db`, `user`, `pass` will have to be configured in the `PostgreSQL configuration` section - `host` is the name of the postgres container (eg: *firefish_db_1*), and the others should match your `docker.env`.
|
||||
- `host`will need to be configured in the *Redis configuration* section - it is the name of the redis container (eg: *firefish_redis_1*)
|
||||
- `auth` will need to be configured in the *Sonic* section - cannot be the default `SecretPassword`
|
||||
|
||||
Everything else can be left as-is.
|
||||
|
||||
## Running docker-compose
|
||||
|
||||
The [prebuilt container for firefish](https://hub.docker.com/r/thatonecalculator/firefish) is fairly large, and may take a few minutes to download and extract using docker.
|
||||
|
||||
Copy `docker-compose.yml` and the `config/` to a directory, then run the **docker-compose** command:
|
||||
`docker-compose up -d`.
|
||||
|
||||
NOTE: This will take some time to come fully online, even after download and extracting the container images, and it may emit some error messages before completing successfully. Specifically, the `db` container needs to initialize and so isn't available to the `web` container right away. Only once the `db` container comes online does the `web` container start building and initializing the firefish tables.
|
||||
|
||||
Once the server is up you can use a web browser to access the web interface at `http://serverip:3000` (where `serverip` is the IP of the server you are running the firefish server on).
|
||||
|
||||
## Docker for development
|
||||
|
||||
```sh
|
||||
cd dev/
|
||||
docker-compose build
|
||||
docker-compose run --rm web pnpm run init
|
||||
docker-compose up -d
|
||||
```
|
41
docs/fk.patch
Normal file
41
docs/fk.patch
Normal file
|
@ -0,0 +1,41 @@
|
|||
diff --git a/packages/backend/migration/1661376843000-remove-mentioned-remote-users-column.js b/packages/backend/migration/1661376843000-remove-mentioned-remote-users-column.js
|
||||
index 42d79b5b5..1fd5e0f10 100644
|
||||
--- a/packages/backend/migration/1661376843000-remove-mentioned-remote-users-column.js
|
||||
+++ b/packages/backend/migration/1661376843000-remove-mentioned-remote-users-column.js
|
||||
@@ -7,6 +7,22 @@ export class removeMentionedRemoteUsersColumn1661376843000 {
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "note" ADD "mentionedRemoteUsers" TEXT NOT NULL DEFAULT '[]'::text`);
|
||||
- await queryRunner.query(`UPDATE "note" SET "mentionedRemoteUsers" = (SELECT COALESCE(json_agg(row_to_json("data"))::text, '[]') FROM (SELECT "url", "uri", "username", "host" FROM "user" JOIN "user_profile" ON "user"."id" = "user_profile". "userId" WHERE "user"."host" IS NOT NULL AND "user"."id" = ANY("note"."mentions")) AS "data")`);
|
||||
+ await queryRunner.query(`
|
||||
+ CREATE TEMP TABLE IF NOT EXISTS "temp_mentions" AS
|
||||
+ SELECT "id", "url", "uri", "username", "host"
|
||||
+ FROM "user"
|
||||
+ JOIN "user_profile" ON "user"."id" = "user_profile"."userId" WHERE "user"."host" IS NOT NULL
|
||||
+ `);
|
||||
+
|
||||
+ await queryRunner.query(`
|
||||
+ CREATE UNIQUE INDEX "temp_mentions_id" ON "temp_mentions"("id")
|
||||
+ `);
|
||||
+
|
||||
+ await queryRunner.query(`
|
||||
+ UPDATE "note" SET "mentionedRemoteUsers" = (
|
||||
+ SELECT COALESCE(json_agg(row_to_json("data")::jsonb - 'id')::text, '[]') FROM "temp_mentions" AS "data"
|
||||
+ WHERE "data"."id" = ANY("note"."mentions")
|
||||
+ )
|
||||
+ `);
|
||||
}
|
||||
}
|
||||
diff --git a/packages/backend/migration/1663399074403-resize-comments-drive-file.js b/packages/backend/migration/1663399074403-resize-comments-drive-file.js
|
||||
index a037f1655..0873aec9b 100644
|
||||
--- a/packages/backend/migration/1663399074403-resize-comments-drive-file.js
|
||||
+++ b/packages/backend/migration/1663399074403-resize-comments-drive-file.js
|
||||
@@ -9,6 +9,6 @@ export class resizeCommentsDriveFile1663399074403 {
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "comment" TYPE character varying(512)`);
|
||||
- }
|
||||
+ console.log('This migration cannot be reverted, skipping...');
|
||||
+ }
|
||||
}
|
45
docs/kubernetes.md
Normal file
45
docs/kubernetes.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
# Running a Firefish server with Kubernetes and Helm
|
||||
|
||||
This is a [Helm](https://helm.sh/) chart directory in the root of the project
|
||||
that you can use to deploy firefish to a Kubernetes cluster
|
||||
|
||||
## Deployment
|
||||
|
||||
1. Copy the example helm values and make your changes:
|
||||
```shell
|
||||
cp .config/helm_values_example.yml .config/helm_values.yml
|
||||
```
|
||||
|
||||
2. Update helm dependencies:
|
||||
```shell
|
||||
cd chart
|
||||
helm dependency list $dir 2> /dev/null | tail +2 | head -n -1 | awk '{ print "helm repo add " $1 " " $3 }' | while read cmd; do $cmd; done;
|
||||
cd ../
|
||||
```
|
||||
|
||||
3. Create the firefish helm release (also used to update existing deployment):
|
||||
```shell
|
||||
helm upgrade \
|
||||
--install \
|
||||
--namespace firefish \
|
||||
--create-namespace \
|
||||
firefish chart/ \
|
||||
-f .config/helm_values.yml
|
||||
```
|
||||
|
||||
4. Watch your firefish server spin up:
|
||||
```shell
|
||||
kubectl -n firefish get po -w
|
||||
```
|
||||
|
||||
5. Initial the admin user and managed config:
|
||||
```shell
|
||||
export firefish_USERNAME="my_desired_admin_handle" && \
|
||||
export firefish_PASSWORD="myDesiredInitialPassword" && \
|
||||
export firefish_HOST="firefish.example.com" && \
|
||||
export firefish_TOKEN=$(curl -X POST https://$firefish_HOST/api/admin/accounts/create -H "Content-Type: application/json" -d "{ \"username\":\"$firefish_USERNAME\", \"password\":\"$firefish_PASSWORD\" }" | jq -r '.token') && \
|
||||
echo "Save this token: ${firefish_TOKEN}" && \
|
||||
curl -X POST -H "Authorization: Bearer $firefish_TOKEN" https://$firefish_HOST/api/admin/accounts/hosted
|
||||
```
|
||||
|
||||
6. Enjoy!
|
106
docs/migrate.md
Normal file
106
docs/migrate.md
Normal file
|
@ -0,0 +1,106 @@
|
|||
# 🚚 Migrating from Misskey/FoundKey to Firefish
|
||||
|
||||
All the guides below assume you're starting in the root of the repo directory.
|
||||
|
||||
### Before proceeding
|
||||
|
||||
- **Ensure you have stopped all master and worker processes of Misskey.**
|
||||
- **Ensure you have backups of the database before performing any commands.**
|
||||
|
||||
## Misskey v13 and above
|
||||
|
||||
Tested with Misskey v13.11.3.
|
||||
|
||||
If your Misskey v13 is older, we recommend updating your Misskey to v13.11.3.
|
||||
|
||||
```sh
|
||||
wget -O mkv13.patch https://gitlab.prometheus.systems/firefish/firefish/-/raw/develop/docs/mkv13.patch
|
||||
wget -O mkv13_restore.patch https://gitlab.prometheus.systems/firefish/firefish/-/raw/develop/docs/mkv13_restore.patch
|
||||
git apply mkv13.patch mkv13_restore.patch
|
||||
|
||||
cd packages/backend
|
||||
|
||||
LINE_NUM="$(pnpm typeorm migration:show -d ormconfig.js | grep -n activeEmailValidation1657346559800 | cut -d ':' -f 1)"
|
||||
NUM_MIGRATIONS="$(pnpm typeorm migration:show -d ormconfig.js | tail -n+"$LINE_NUM" | grep '\[X\]' | wc -l)"
|
||||
|
||||
for i in $(seq 1 $NUM_MIGRATIONS); do pnpm typeorm migration:revert -d ormconfig.js; done
|
||||
|
||||
cd ../../
|
||||
|
||||
git remote set-url origin https://gitlab.prometheus.systems/firefish/firefish.git
|
||||
git fetch origin
|
||||
git stash push
|
||||
rm -rf fluent-emojis misskey-assets
|
||||
git switch main # or beta or develop
|
||||
git pull --ff
|
||||
wget -O renote_muting.patch https://gitlab.prometheus.systems/firefish/firefish/-/raw/develop/docs/renote_muting.patch
|
||||
git apply renote_muting.patch
|
||||
|
||||
pnpm install
|
||||
NODE_ENV=production pnpm run build
|
||||
pnpm run migrate
|
||||
git stash push
|
||||
```
|
||||
|
||||
Depending on the version you're migrating from, you may have to open Postgres with `psql -d your_database` and run the following commands:
|
||||
|
||||
```sql
|
||||
ALTER TABLE "meta" ADD COLUMN "disableLocalTimeline" boolean DEFAULT false;
|
||||
ALTER TABLE "meta" ADD COLUMN "disableGlobalTimeline" boolean DEFAULT false;
|
||||
ALTER TABLE "meta" ADD COLUMN "localDriveCapacityMb" integer DEFAULT 512;
|
||||
ALTER TABLE "meta" ADD COLUMN "remoteDriveCapacityMb" integer DEFAULT 128;
|
||||
ALTER TABLE "user" ADD COLUMN "isSilenced" boolean DEFAULT false;
|
||||
ALTER TABLE "user" ADD COLUMN "isAdmin" boolean DEFAULT false;
|
||||
ALTER TABLE "user" ADD COLUMN "isModerator" boolean DEFAULT false;
|
||||
ALTER TABLE "user" ADD COLUMN "remoteDriveCapacityMb" integer DEFAULT 128;
|
||||
ALTER TABLE "user" ADD COLUMN "driveCapacityOverrideMb" integer DEFAULT 128;
|
||||
ALTER TABLE "instance" ADD COLUMN "caughtAt" date;
|
||||
ALTER TABLE "instance" ADD COLUMN "latestRequestSentAt" date;
|
||||
ALTER TABLE "instance" ADD COLUMN "latestStatus" character varying(512);
|
||||
ALTER TABLE "instance" ADD COLUMN "lastCommunicatedAt" date;
|
||||
```
|
||||
|
||||
then quit with `\q`, and restart Firefish.
|
||||
|
||||
Note: Ignore errors of `column "xxx" of relation "xxx" already exists`.
|
||||
|
||||
If no other errors happened, your Firefish is ready to launch!
|
||||
|
||||
## Misskey v12.119 and before
|
||||
|
||||
```sh
|
||||
git remote set-url origin https://gitlab.prometheus.systems/firefish/firefish.git
|
||||
git fetch
|
||||
git checkout main # or beta or develop
|
||||
git pull --ff
|
||||
|
||||
NODE_ENV=production pnpm run migrate
|
||||
# build using prefered method
|
||||
```
|
||||
|
||||
## FoundKey
|
||||
|
||||
```sh
|
||||
wget -O fk.patch https://gitlab.prometheus.systems/firefish/firefish/-/raw/develop/docs/fk.patch
|
||||
git apply fk.patch
|
||||
cd packages/backend
|
||||
|
||||
LINE_NUM="$(npx typeorm migration:show -d ormconfig.js | grep -n uniformThemecolor1652859567549 | cut -d ':' -f 1)"
|
||||
NUM_MIGRATIONS="$(npx typeorm migration:show -d ormconfig.js | tail -n+"$LINE_NUM" | grep '\[X\]' | wc -l)"
|
||||
|
||||
for i in $(seq 1 $NUM_MIGRATIONS); do
|
||||
npx typeorm migration:revert -d ormconfig.js
|
||||
done
|
||||
|
||||
git remote set-url origin https://gitlab.prometheus.systems/firefish/firefish.git
|
||||
git fetch
|
||||
git checkout main # or beta or develop
|
||||
git pull --ff
|
||||
|
||||
NODE_ENV=production pnpm run migrate
|
||||
# build using prefered method
|
||||
```
|
||||
|
||||
## Reverse
|
||||
|
||||
You ***cannot*** migrate back to Misskey from Firefish due to re-hashing passwords on signin with argon2. You can migrate from Calckey to FoundKey, although this is not recommended due to FoundKey being end-of-life, and may have some problems with alt-text.
|
45
docs/mkv13.patch
Normal file
45
docs/mkv13.patch
Normal file
|
@ -0,0 +1,45 @@
|
|||
diff --git a/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js b/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js
|
||||
index 38a676985..c4ae690e0 100644
|
||||
--- a/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js
|
||||
+++ b/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js
|
||||
@@ -6,6 +6,8 @@ export class removeLastCommunicatedAt1672704017999 {
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
- await queryRunner.query(`ALTER TABLE "instance" ADD "lastCommunicatedAt" TIMESTAMP WITH TIME ZONE NOT NULL`);
|
||||
+ await queryRunner.query(`ALTER TABLE "instance" ADD "lastCommunicatedAt" TIMESTAMP WITH TIME ZONE`);
|
||||
+ await queryRunner.query(`UPDATE "instance" SET "lastCommunicatedAt" = COALESCE("infoUpdatedAt", "caughtAt")`);
|
||||
+ await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "lastCommunicatedAt" SET NOT NULL`);
|
||||
}
|
||||
}
|
||||
diff --git a/packages/backend/migration/1673336077243-PollChoiceLength.js b/packages/backend/migration/1673336077243-PollChoiceLength.js
|
||||
index 810c626e0..5809528cb 100644
|
||||
--- a/packages/backend/migration/1673336077243-PollChoiceLength.js
|
||||
+++ b/packages/backend/migration/1673336077243-PollChoiceLength.js
|
||||
@@ -6,6 +6,6 @@ export class PollChoiceLength1673336077243 {
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
- await queryRunner.query(`ALTER TABLE "poll" ALTER COLUMN "choices" TYPE character varying(128) array`);
|
||||
+ //await queryRunner.query(`ALTER TABLE "poll" ALTER COLUMN "choices" TYPE character varying(128) array`);
|
||||
}
|
||||
}
|
||||
diff --git a/packages/backend/migration/1674118260469-achievement.js b/packages/backend/migration/1674118260469-achievement.js
|
||||
index 131ab96f8..57a922f83 100644
|
||||
--- a/packages/backend/migration/1674118260469-achievement.js
|
||||
+++ b/packages/backend/migration/1674118260469-achievement.js
|
||||
@@ -18,12 +18,13 @@ export class achievement1674118260469 {
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`CREATE TYPE "public"."user_profile_mutingnotificationtypes_enum_old" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'pollEnded')`);
|
||||
+ await queryRunner.query(`CREATE TYPE "public"."notification_type_enum_old" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app')`);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" DROP DEFAULT`);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" TYPE "public"."user_profile_mutingnotificationtypes_enum_old"[] USING "mutingNotificationTypes"::"text"::"public"."user_profile_mutingnotificationtypes_enum_old"[]`);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" SET DEFAULT '{}'`);
|
||||
await queryRunner.query(`DROP TYPE "public"."user_profile_mutingnotificationtypes_enum"`);
|
||||
await queryRunner.query(`ALTER TYPE "public"."user_profile_mutingnotificationtypes_enum_old" RENAME TO "user_profile_mutingnotificationtypes_enum"`);
|
||||
- await queryRunner.query(`CREATE TYPE "public"."notification_type_enum_old" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app')`);
|
||||
+ await queryRunner.query(`DELETE FROM "public"."notification" WHERE "type" = 'achievementEarned'`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" ALTER COLUMN "type" TYPE "public"."notification_type_enum_old" USING "type"::"text"::"public"."notification_type_enum_old"`);
|
||||
await queryRunner.query(`DROP TYPE "public"."notification_type_enum"`);
|
||||
await queryRunner.query(`ALTER TYPE "public"."notification_type_enum_old" RENAME TO "notification_type_enum"`);
|
127
docs/mkv13_restore.patch
Normal file
127
docs/mkv13_restore.patch
Normal file
|
@ -0,0 +1,127 @@
|
|||
diff --git a/packages/backend/migration/1680491187535-cleanup.js b/packages/backend/migration/1680491187535-cleanup.js
|
||||
index 1e609ca06..0e6accf3e 100644
|
||||
--- a/packages/backend/migration/1680491187535-cleanup.js
|
||||
+++ b/packages/backend/migration/1680491187535-cleanup.js
|
||||
@@ -1,10 +1,40 @@
|
||||
export class cleanup1680491187535 {
|
||||
- name = 'cleanup1680491187535'
|
||||
+ name = "cleanup1680491187535";
|
||||
|
||||
- async up(queryRunner) {
|
||||
- await queryRunner.query(`DROP TABLE "antenna_note" `);
|
||||
- }
|
||||
+ async up(queryRunner) {
|
||||
+ await queryRunner.query(`DROP TABLE "antenna_note" `);
|
||||
+ }
|
||||
|
||||
- async down(queryRunner) {
|
||||
- }
|
||||
+ async down(queryRunner) {
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE TABLE antenna_note ( id character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "antennaId" character varying(32) NOT NULL, read boolean DEFAULT false NOT NULL)`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `COMMENT ON COLUMN antenna_note."noteId" IS 'The note ID.'`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `COMMENT ON COLUMN antenna_note."antennaId" IS 'The antenna ID.'`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY antenna_note ADD CONSTRAINT "PK_fb28d94d0989a3872df19fd6ef8" PRIMARY KEY (id)`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_0d775946662d2575dfd2068a5f" ON antenna_note USING btree ("antennaId")`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE UNIQUE INDEX "IDX_335a0bf3f904406f9ef3dd51c2" ON antenna_note USING btree ("noteId", "antennaId")`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_9937ea48d7ae97ffb4f3f063a4" ON antenna_note USING btree (read)`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_bd0397be22147e17210940e125" ON antenna_note USING btree ("noteId")`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY antenna_note ADD CONSTRAINT "FK_0d775946662d2575dfd2068a5f5" FOREIGN KEY ("antennaId") REFERENCES antenna(id) ON DELETE CASCADE`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY antenna_note ADD CONSTRAINT "FK_bd0397be22147e17210940e125b" FOREIGN KEY ("noteId") REFERENCES note(id) ON DELETE CASCADE`,
|
||||
+ );
|
||||
+ }
|
||||
}
|
||||
diff --git a/packages/backend/migration/1680582195041-cleanup.js b/packages/backend/migration/1680582195041-cleanup.js
|
||||
index c587e456a..a91d6ff3c 100644
|
||||
--- a/packages/backend/migration/1680582195041-cleanup.js
|
||||
+++ b/packages/backend/migration/1680582195041-cleanup.js
|
||||
@@ -1,11 +1,64 @@
|
||||
export class cleanup1680582195041 {
|
||||
- name = 'cleanup1680582195041'
|
||||
+ name = "cleanup1680582195041";
|
||||
|
||||
- async up(queryRunner) {
|
||||
- await queryRunner.query(`DROP TABLE "notification" `);
|
||||
- }
|
||||
+ async up(queryRunner) {
|
||||
+ await queryRunner.query(`DROP TABLE "notification"`);
|
||||
+ }
|
||||
|
||||
- async down(queryRunner) {
|
||||
-
|
||||
- }
|
||||
+ async down(queryRunner) {
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE TABLE notification ( id character varying(32) NOT NULL, "createdAt" timestamp with time zone NOT NULL, "notifieeId" character varying(32) NOT NULL, "notifierId" character varying(32), "isRead" boolean DEFAULT false NOT NULL, "noteId" character varying(32), reaction character varying(128), choice integer, "followRequestId" character varying(32), type notification_type_enum NOT NULL, "customBody" character varying(2048), "customHeader" character varying(256), "customIcon" character varying(1024), "appAccessTokenId" character varying(32), achievement character varying(128))`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `COMMENT ON COLUMN notification."createdAt" IS 'The created date of the Notification.'`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `COMMENT ON COLUMN notification."notifieeId" IS 'The ID of recipient user of the Notification.'`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `COMMENT ON COLUMN notification."notifierId" IS 'The ID of sender user of the Notification.'`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `COMMENT ON COLUMN notification."isRead" IS 'Whether the Notification is read.'`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `COMMENT ON COLUMN notification.type IS 'The type of the Notification.'`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "PK_705b6c7cdf9b2c2ff7ac7872cb7" PRIMARY KEY (id)`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_080ab397c379af09b9d2169e5b" ON notification USING btree ("isRead")`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_33f33cc8ef29d805a97ff4628b" ON notification USING btree (type)`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_3b4e96eec8d36a8bbb9d02aa71" ON notification USING btree ("notifierId")`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_3c601b70a1066d2c8b517094cb" ON notification USING btree ("notifieeId")`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_b11a5e627c41d4dc3170f1d370" ON notification USING btree ("createdAt")`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `CREATE INDEX "IDX_e22bf6bda77b6adc1fd9e75c8c" ON notification USING btree ("appAccessTokenId")`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_3b4e96eec8d36a8bbb9d02aa710" FOREIGN KEY ("notifierId") REFERENCES "user"(id) ON DELETE CASCADE`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_3c601b70a1066d2c8b517094cb9" FOREIGN KEY ("notifieeId") REFERENCES "user"(id) ON DELETE CASCADE`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_769cb6b73a1efe22ddf733ac453" FOREIGN KEY ("noteId") REFERENCES note(id) ON DELETE CASCADE`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_bd7fab507621e635b32cd31892c" FOREIGN KEY ("followRequestId") REFERENCES follow_request(id) ON DELETE CASCADE`,
|
||||
+ );
|
||||
+ await queryRunner.query(
|
||||
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_e22bf6bda77b6adc1fd9e75c8c9" FOREIGN KEY ("appAccessTokenId") REFERENCES access_token(id) ON DELETE CASCADE`,
|
||||
+ );
|
||||
+ }
|
||||
}
|
23
docs/renote_muting.patch
Normal file
23
docs/renote_muting.patch
Normal file
|
@ -0,0 +1,23 @@
|
|||
diff --git a/packages/backend/migration/1665091090561-add-renote-muting.js b/packages/backend/migration/1665091090561-add-renote-muting.js
|
||||
index 2c76aaff5..f8541c818 100644
|
||||
--- a/packages/backend/migration/1665091090561-add-renote-muting.js
|
||||
+++ b/packages/backend/migration/1665091090561-add-renote-muting.js
|
||||
@@ -4,18 +4,6 @@ export class addRenoteMuting1665091090561 {
|
||||
}
|
||||
|
||||
async up(queryRunner) {
|
||||
- await queryRunner.query(
|
||||
- `CREATE TABLE "renote_muting" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "muteeId" character varying(32) NOT NULL, "muterId" character varying(32) NOT NULL, CONSTRAINT "PK_renoteMuting_id" PRIMARY KEY ("id"))`,
|
||||
- );
|
||||
- await queryRunner.query(
|
||||
- `CREATE INDEX "IDX_renote_muting_createdAt" ON "muting" ("createdAt") `,
|
||||
- );
|
||||
- await queryRunner.query(
|
||||
- `CREATE INDEX "IDX_renote_muting_muteeId" ON "muting" ("muteeId") `,
|
||||
- );
|
||||
- await queryRunner.query(
|
||||
- `CREATE INDEX "IDX_renote_muting_muterId" ON "muting" ("muterId") `,
|
||||
- );
|
||||
}
|
||||
|
||||
async down(queryRunner) {}
|
13
firefish.apache.conf
Normal file
13
firefish.apache.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Replace example.tld with your domain
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName example.tld
|
||||
# For WebSocket
|
||||
ProxyPass "/streaming" "ws://127.0.0.1:3000/streaming/"
|
||||
# Proxy to Node
|
||||
ProxyPass "/" "http://127.0.0.1:3000/"
|
||||
ProxyPassReverse "/" "http://127.0.0.1:3000/"
|
||||
ProxyPreserveHost On
|
||||
# For files proxy
|
||||
AllowEncodedSlashes On
|
||||
</VirtualHost>
|
72
firefish.nginx.conf
Normal file
72
firefish.nginx.conf
Normal file
|
@ -0,0 +1,72 @@
|
|||
# Replace example.tld with your domain
|
||||
|
||||
# For WebSocket
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name example.tld;
|
||||
|
||||
# For SSL domain validation
|
||||
root /var/www/html;
|
||||
location /.well-known/acme-challenge/ { allow all; }
|
||||
location /.well-known/pki-validation/ { allow all; }
|
||||
location / { return 301 https://$server_name$request_uri; }
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name example.tld;
|
||||
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:ssl_session_cache:10m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
# To use Let's Encrypt certificate
|
||||
ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem;
|
||||
|
||||
# To use Debian/Ubuntu's self-signed certificate (For testing or before issuing a certificate)
|
||||
#ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
|
||||
#ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
|
||||
|
||||
# SSL protocol settings
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
# Change to your upload limit
|
||||
client_max_body_size 80m;
|
||||
|
||||
# Proxy to Node
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_http_version 1.1;
|
||||
proxy_redirect off;
|
||||
|
||||
# If it's behind another reverse proxy or CDN, remove the following.
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
|
||||
# For WebSocket
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
# Cache settings
|
||||
proxy_cache cache1;
|
||||
proxy_cache_lock on;
|
||||
proxy_cache_use_stale updating;
|
||||
add_header X-Cache $upstream_cache_status;
|
||||
}
|
||||
}
|
294
flake.lock
Normal file
294
flake.lock
Normal file
|
@ -0,0 +1,294 @@
|
|||
{
|
||||
"nodes": {
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1685521914,
|
||||
"narHash": "sha256-0fdFP5IASLwJ0PSXrErW8PZon9TVYmi8VRF8OtjGkV4=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "e206d8f2e3e8d6aa943656052f15bdfea8146b8d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1685514167,
|
||||
"narHash": "sha256-urRxF0ZGSNeZjM4kALNg3wTh7fBscbqQmS6S/HU7Wms=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "3abfea51663583186f687c49a157eab1639349ca",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1685457039,
|
||||
"narHash": "sha256-bEFtQm+YyLxQjKQAaBHJyPN1z2wbhBnr2g1NJWSYjwM=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "80717d11615b6f42d1ad2e18ead51193fc15de69",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1660459072,
|
||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lowdown-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1633514407,
|
||||
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"lowdown-src": "lowdown-src",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1676545802,
|
||||
"narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "relaxed-flakes",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1678875422,
|
||||
"narHash": "sha256-T3o6NcQPwXjxJMn2shz86Chch4ljXgZn746c2caGxd8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "126f49a01de5b7e35a43fd43f891ecf6d3a51459",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"dir": "lib",
|
||||
"lastModified": 1682879489,
|
||||
"narHash": "sha256-sASwo8gBt7JDnOOstnps90K1wxmVfyhsTPPNTGBPjjg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "da45bf6ec7bbcc5d1e14d3795c025199f28e0de0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "lib",
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression": {
|
||||
"locked": {
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1678872516,
|
||||
"narHash": "sha256-/E1YwtMtFAu2KUQKV/1+KFuReYPANM2Rzehk84VxVoc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9b8e5abb18324c7fe9f07cb100c3cd4a29cda8b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-22.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1685399834,
|
||||
"narHash": "sha256-Lt7//5snriXSdJo5hlVcDkpERL1piiih0UXIz1RUcC4=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "58c85835512b0db938600b6fe13cc3e3dc4b364e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"flake-utils": "flake-utils",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1682596858,
|
||||
"narHash": "sha256-Hf9XVpqaGqe/4oDGr30W8HlsWvJXtMsEPHDqHZA6dDg=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "fb58866e20af98779017134319b5663b8215d912",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"fenix": "fenix",
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1685465261,
|
||||
"narHash": "sha256-aJ2nUinUrNcFi+pb47bS5IIAeSiUEEPLJY8W4Q8Pcjk=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "d2b3caa5b5694125fad04a9699e919444439f6a2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
86
flake.nix
Normal file
86
flake.nix
Normal file
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
description = "Firefish development flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||
# Flake Parts framework(https://flake.parts)
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
# Devenv for better devShells(https://devenv.sh)
|
||||
devenv.url = "github:cachix/devenv";
|
||||
# Fenix for rust development
|
||||
fenix.url = "github:nix-community/fenix";
|
||||
fenix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
outputs = inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [
|
||||
inputs.devenv.flakeModule
|
||||
];
|
||||
|
||||
# Define the systems that this works on. Only tested with x66_64-linux, add more if you test and it works.
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
];
|
||||
# Expose these attributes for every system defined above.
|
||||
perSystem = { config, pkgs, ... }: {
|
||||
# Devenv shells
|
||||
devenv = {
|
||||
shells = {
|
||||
# The default shell, used by nix-direnv
|
||||
default = {
|
||||
name = "firefish-dev-shell";
|
||||
# Add additional packages to our environment
|
||||
packages = [
|
||||
pkgs.nodePackages.pnpm
|
||||
|
||||
pkgs.python3
|
||||
];
|
||||
# No need to warn on a new version, we'll update as needed.
|
||||
devenv.warnOnNewVersion = false;
|
||||
# Enable typescript support
|
||||
languages.typescript.enable = true;
|
||||
# Enable javascript for NPM and PNPM
|
||||
languages.javascript.enable = true;
|
||||
languages.javascript.package = pkgs.nodejs_18;
|
||||
# Enable stable Rust for the backend
|
||||
languages.rust.enable = true;
|
||||
languages.rust.version = "stable";
|
||||
processes = {
|
||||
dev-server.exec = "pnpm run dev";
|
||||
};
|
||||
scripts = {
|
||||
build.exec = "pnpm run build";
|
||||
clean.exec = "pnpm run clean";
|
||||
clear-state.exec = "rm -rf .devenv/state/redis .devenv/state/postgres";
|
||||
format.exec = "pnpm run format";
|
||||
install-deps.exec = "pnpm install";
|
||||
migrate.exec = "pnpm run migrate";
|
||||
prepare-config.exec = "cp .config/devenv.yml .config/default.yml";
|
||||
};
|
||||
services = {
|
||||
postgres = {
|
||||
enable = true;
|
||||
package = pkgs.postgresql_12;
|
||||
initialDatabases = [{
|
||||
name = "firefish";
|
||||
}];
|
||||
initialScript = ''
|
||||
CREATE USER firefish WITH PASSWORD 'firefish';
|
||||
ALTER USER firefish WITH SUPERUSER;
|
||||
GRANT ALL ON DATABASE firefish TO firefish;
|
||||
'';
|
||||
listen_addresses = "127.0.0.1";
|
||||
port = 5432;
|
||||
};
|
||||
redis = {
|
||||
enable = true;
|
||||
bind = "127.0.0.1";
|
||||
port = 6379;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
99
gulpfile.js
Normal file
99
gulpfile.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Gulp tasks
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const gulp = require("gulp");
|
||||
const replace = require("gulp-replace");
|
||||
const terser = require("gulp-terser");
|
||||
const cssnano = require("gulp-cssnano");
|
||||
|
||||
const locales = require("./locales");
|
||||
const meta = require("./package.json");
|
||||
|
||||
gulp.task("copy:backend:views", () =>
|
||||
gulp
|
||||
.src("./packages/backend/src/server/web/views/**/*")
|
||||
.pipe(gulp.dest("./packages/backend/built/server/web/views")),
|
||||
);
|
||||
|
||||
gulp.task("copy:backend:custom", () =>
|
||||
gulp
|
||||
.src("./custom/assets/**/*")
|
||||
.pipe(gulp.dest("./packages/backend/assets/")),
|
||||
);
|
||||
|
||||
gulp.task("copy:client:fonts", () =>
|
||||
gulp
|
||||
.src("./packages/client/node_modules/three/examples/fonts/**/*")
|
||||
.pipe(gulp.dest("./built/_client_dist_/fonts/")),
|
||||
);
|
||||
|
||||
gulp.task("copy:client:locales", (cb) => {
|
||||
fs.mkdirSync("./built/_client_dist_/locales", { recursive: true });
|
||||
|
||||
const v = { _version_: meta.version };
|
||||
|
||||
for (const [lang, locale] of Object.entries(locales)) {
|
||||
fs.writeFileSync(
|
||||
`./built/_client_dist_/locales/${lang}.${meta.version}.json`,
|
||||
JSON.stringify({ ...locale, ...v }),
|
||||
"utf-8",
|
||||
);
|
||||
}
|
||||
|
||||
cb();
|
||||
});
|
||||
|
||||
gulp.task("build:backend:script", () => {
|
||||
return gulp
|
||||
.src([
|
||||
"./packages/backend/src/server/web/boot.js",
|
||||
"./packages/backend/src/server/web/bios.js",
|
||||
"./packages/backend/src/server/web/cli.js",
|
||||
])
|
||||
.pipe(replace("LANGS", JSON.stringify(Object.keys(locales))))
|
||||
.pipe(
|
||||
terser({
|
||||
toplevel: true,
|
||||
}),
|
||||
)
|
||||
.pipe(gulp.dest("./packages/backend/built/server/web/"));
|
||||
});
|
||||
|
||||
gulp.task("build:backend:style", () => {
|
||||
return gulp
|
||||
.src([
|
||||
"./packages/backend/src/server/web/style.css",
|
||||
"./packages/backend/src/server/web/bios.css",
|
||||
"./packages/backend/src/server/web/cli.css",
|
||||
])
|
||||
.pipe(
|
||||
cssnano({
|
||||
zindex: false,
|
||||
}),
|
||||
)
|
||||
.pipe(gulp.dest("./packages/backend/built/server/web/"));
|
||||
});
|
||||
|
||||
gulp.task(
|
||||
"build",
|
||||
gulp.parallel(
|
||||
"copy:client:locales",
|
||||
"copy:backend:views",
|
||||
"copy:backend:custom",
|
||||
"build:backend:script",
|
||||
"build:backend:style",
|
||||
"copy:client:fonts",
|
||||
),
|
||||
);
|
||||
|
||||
gulp.task("default", gulp.task("build"));
|
||||
|
||||
gulp.task("watch", () => {
|
||||
gulp.watch(
|
||||
["./packages/*/src/**/*"],
|
||||
{ ignoreInitial: false },
|
||||
gulp.task("build"),
|
||||
);
|
||||
});
|
136
issue_template/bug.yaml
Normal file
136
issue_template/bug.yaml
Normal file
|
@ -0,0 +1,136 @@
|
|||
name: 🐛 Bug Report
|
||||
about: File a bug report
|
||||
title: "[Bug]: "
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 💁 Support Matrix
|
||||
url: https://matrix.to/#/%23firefish:matrix.fedibird.com
|
||||
about: Having trouble with deployment? Ask the support chat.
|
||||
- name: 🔒 Resposible Disclosure
|
||||
url: https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/SECURITY.md
|
||||
about: Found a security vulnerability? Please disclose it responsibly.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
💖 Thanks for taking the time to fill out this bug report!
|
||||
💁 Having trouble with deployment? [Ask the support chat.](https://matrix.to/#/%23firefish:matrix.fedibird.com)
|
||||
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/SECURITY.md)
|
||||
🤝 By submitting this issue, you agree to follow our [Contribution Guidelines.](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/CONTRIBUTING.md)
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Please give us a brief description of what happened.
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what-is-expected
|
||||
attributes:
|
||||
label: What did you expect to happen?
|
||||
description: Please give us a brief description of what you expected to happen.
|
||||
placeholder: Tell us what you wish happened!
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.
|
||||
placeholder: v13.1.4.1
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: instance
|
||||
attributes:
|
||||
label: Instance
|
||||
description: What instance of firefish are you using?
|
||||
placeholder: firefish.social
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: issue-type
|
||||
attributes:
|
||||
label: What type of issue is this?
|
||||
description: If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side.
|
||||
multiple: false
|
||||
options:
|
||||
- Client-side
|
||||
- Server-side
|
||||
- Other (Please Specify)
|
||||
- type: dropdown
|
||||
id: browsers
|
||||
attributes:
|
||||
label: What browser are you using? (Client-side issues only)
|
||||
multiple: false
|
||||
options:
|
||||
- N/A
|
||||
- Firefox
|
||||
- Chrome
|
||||
- Brave
|
||||
- Librewolf
|
||||
- Chromium
|
||||
- Safari
|
||||
- Microsoft Edge
|
||||
- Other (Please Specify)
|
||||
- type: dropdown
|
||||
id: device
|
||||
attributes:
|
||||
label: What operating system are you using? (Client-side issues only)
|
||||
multiple: false
|
||||
options:
|
||||
- N/A
|
||||
- Windows
|
||||
- MacOS
|
||||
- Linux
|
||||
- Android
|
||||
- iOS
|
||||
- Other (Please Specify)
|
||||
- type: dropdown
|
||||
id: deplotment-method
|
||||
attributes:
|
||||
label: How do you deploy Firefish on your server? (Server-side issues only)
|
||||
multiple: false
|
||||
options:
|
||||
- N/A
|
||||
- Manual
|
||||
- Ubuntu Install Script
|
||||
- Docker Compose
|
||||
- Docker Prebuilt Image
|
||||
- Helm Chart
|
||||
- YunoHost
|
||||
- AUR Package
|
||||
- Other (Please Specify)
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you using? (Server-side issues only)
|
||||
multiple: false
|
||||
options:
|
||||
- N/A
|
||||
- Ubuntu >= 22.04
|
||||
- Ubuntu < 22.04
|
||||
- Debian
|
||||
- Arch
|
||||
- RHEL (CentOS/AlmaLinux/Rocky Linux)
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- Android
|
||||
- Other (Please Specify)
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Contribution Guidelines
|
||||
description: By submitting this issue, you agree to follow our [Contribution Guidelines](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/CONTRIBUTING.md)
|
||||
options:
|
||||
- label: I agree to follow this project's Contribution Guidelines
|
||||
required: true
|
||||
- label: I have searched the issue tracker for similar issues, and this is not a duplicate.
|
||||
required: true
|
61
issue_template/feature.yaml
Normal file
61
issue_template/feature.yaml
Normal file
|
@ -0,0 +1,61 @@
|
|||
name: ✨ Feature Request
|
||||
about: Request a Feature
|
||||
title: "[Feature]: "
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 💁 Support Matrix
|
||||
url: https://matrix.to/#/%23firefish:matrix.fedibird.com
|
||||
about: Having trouble with deployment? Ask the support chat.
|
||||
- name: 🔒 Resposible Disclosure
|
||||
url: https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/SECURITY.md
|
||||
about: Found a security vulnerability? Please disclose it responsibly.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
💖 Thanks for taking the time to fill out this feature request!
|
||||
💁 Having trouble with deployment? [Ask the support chat.](https://matrix.to/#/%23firefish:matrix.fedibird.com)
|
||||
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/SECURITY.md)
|
||||
🤝 By submitting this issue, you agree to follow our [Contribution Guidelines.](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/CONTRIBUTING.md)
|
||||
- type: textarea
|
||||
id: what-feature
|
||||
attributes:
|
||||
label: What feature would you like implemented?
|
||||
description: Please give us a brief description of what you'd like.
|
||||
placeholder: Tell us what you want!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: why-add-feature
|
||||
attributes:
|
||||
label: Why should we add this feature?
|
||||
description: Please give us a brief description of why your feature is important.
|
||||
placeholder: Tell us why you want this feature!
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.
|
||||
placeholder: Firefish Version 13.1.4.1
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: instance
|
||||
attributes:
|
||||
label: Instance
|
||||
description: What instance of firefish are you using?
|
||||
placeholder: firefish.social
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Contribution Guidelines
|
||||
description: By submitting this issue, you agree to follow our [Contribution Guidelines](https://gitlab.prometheus.systems/firefish/firefish/src/branch/develop/CONTRIBUTING.md)
|
||||
options:
|
||||
- label: I agree to follow this project's Contribution Guidelines
|
||||
required: true
|
||||
- label: I have searched the issue tracker for similar requests, and this is not a duplicate.
|
||||
required: true
|
6
locales/README.md
Normal file
6
locales/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# **DO NOT edit locale files** except `ja-JP.yml`.
|
||||
|
||||
When you add text to the ja-JP file (of misskey-dev/misskey), it will automatically be applied to other language files.
|
||||
Translations added in ja-JP file should contain the original Japanese strings.
|
||||
|
||||
Please see [Contribution guide](../CONTRIBUTING.md) for more information.
|
1536
locales/ar-SA.yml
Normal file
1536
locales/ar-SA.yml
Normal file
File diff suppressed because it is too large
Load diff
1661
locales/bn-BD.yml
Normal file
1661
locales/bn-BD.yml
Normal file
File diff suppressed because it is too large
Load diff
1
locales/bul_BG.yml
Normal file
1
locales/bul_BG.yml
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2170
locales/ca-ES.yml
Normal file
2170
locales/ca-ES.yml
Normal file
File diff suppressed because it is too large
Load diff
1009
locales/cs-CZ.yml
Normal file
1009
locales/cs-CZ.yml
Normal file
File diff suppressed because it is too large
Load diff
236
locales/da-DK.yml
Normal file
236
locales/da-DK.yml
Normal file
|
@ -0,0 +1,236 @@
|
|||
_lang_: "Dansk"
|
||||
monthAndDay: '{month}/{day}'
|
||||
search: Søge
|
||||
notifications: Notifikationer
|
||||
username: Brugernavn
|
||||
password: Adgangskode
|
||||
forgotPassword: Glemt adgangskode
|
||||
fetchingAsApObject: Henter fra Fediverset
|
||||
ok: OK
|
||||
gotIt: Forstået!
|
||||
cancel: Annullere
|
||||
enterUsername: Indtast brugernavn
|
||||
instance: Instans
|
||||
renotedBy: Forstærket fra {user}
|
||||
noNotes: Ingen opslag
|
||||
otherSettings: Andre Indstillinger
|
||||
profile: Profil
|
||||
timeline: Tidslinje
|
||||
signup: Registrere
|
||||
logout: Log Ud
|
||||
login: Log ind
|
||||
uploading: Uploader...
|
||||
save: Gem
|
||||
users: Brugere
|
||||
favorited: Tilsat til bogmærker.
|
||||
unfavorite: Fjerne fra bogmærker
|
||||
alreadyFavorited: Allerede inden i bogmærker.
|
||||
pin: Fastgøre til profil
|
||||
unpin: Løse fra profil
|
||||
delete: Slet
|
||||
addToList: Tilsæt til liste
|
||||
deleteAndEdit: Slet og ændre
|
||||
reply: Svar
|
||||
loadMore: Indlæs mere
|
||||
receiveFollowRequest: Følgeanmodning er blevet sendt
|
||||
import: Importere
|
||||
export: Eksportere
|
||||
driveFileDeleteConfirm: Er du sikker på at du vil slette filen "{name}"? Denne vil
|
||||
blive slettet fra alle tilknyttede opslage.
|
||||
unfollowConfirm: Er du sikker på at du vil ikke følge {name} længere?
|
||||
privacy: Privatlivs
|
||||
enterListName: Indtast navnen for denne list
|
||||
makeFollowManuallyApprove: Følgeanmodninger kræver godkendelse
|
||||
unrenote: Fratag forstærkelse
|
||||
renote: Forstærk
|
||||
add: Tilsæt
|
||||
reactionSetting: Reaktioner til at vise i reaktion-vælgeren
|
||||
reactionSettingDescription2: Bevæg til at flytte om på, tryk til at slette og indtast
|
||||
"+" til at tilsætte.
|
||||
rememberNoteVisibility: Husk opslagsynlidhedsindstillinger
|
||||
emojis: Emoji
|
||||
flagShowTimelineReplies: Vis svare i tidslinjen
|
||||
flagAsCatDescription: Du kommer til at få katøre og tale som en kat!
|
||||
showOnRemote: Vis på fjerninstans
|
||||
general: Generelt
|
||||
accountMoved: 'Bruger har flyttet til et nyt konto:'
|
||||
settings: Indstillinger
|
||||
basicSettings: Primær Indstillinger
|
||||
openInWindow: Åben i vindue
|
||||
noAccountDescription: Denne bruger har ikke skrevet deres bio endnu.
|
||||
loggingIn: Logger ind
|
||||
cantFavorite: Kunne ikke tilsætte til bogmærker.
|
||||
copyUsername: Kopi brugernavn
|
||||
copyContent: Kopi indholdet
|
||||
copyLink: Kopi link
|
||||
searchUser: Søg for en bruger
|
||||
files: Filer
|
||||
noLists: Du har ingen liste
|
||||
lists: Lister
|
||||
reaction: Reaktioner
|
||||
sensitive: NSFW
|
||||
emoji: Emoji
|
||||
cacheRemoteFilesDescription: Når denne indstilling er deaktiveret, fremmed filer bliver
|
||||
indlæset direkte fra denne fjerneinstans. Hvis du deaktivere dette så vil det formindske
|
||||
brugte opbevaringsplads men det vil også få netværktraffic til at stige fordi miniaturebilleder
|
||||
vil ikke blive skabt.
|
||||
flagAsBot: Markere denne konto som en robot
|
||||
flagShowTimelineRepliesDescription: Vis svare af brugere til opslage af andre brugere
|
||||
i tidslinjen hvis den bliver tændt.
|
||||
loginFailed: Kunne ikke logge ind
|
||||
silenceThisInstance: Nedtone denne instans
|
||||
deleteAndEditConfirm: Er du sikker på at du vil slet denne opslag og ændre det? Du
|
||||
vil tabe alle reaktioner, forstærkninger og svarer indenfor denne opslag.
|
||||
editNote: Ændre note
|
||||
deleted: Slettet
|
||||
edited: 'Ændret den {date} {time}'
|
||||
sendMessage: Send en besked
|
||||
youShouldUpgradeClient: Til at vise denne side, vær sød at refresh til at opdatere
|
||||
din brugerenhed.
|
||||
defaultNoteVisibility: Standard synlighed
|
||||
follow: Følge
|
||||
followRequest: Følge
|
||||
followRequests: Følgeanmodninger
|
||||
unfollow: Følge ikke længere
|
||||
followRequestPending: Følgeanmodning ventes på
|
||||
enterEmoji: Indtast en emoji
|
||||
renoted: Forstærket.
|
||||
cantRenote: Denne opslag kunne ikke forstærkes.
|
||||
cantReRenote: En forstærkelse kan ikke forstærkes.
|
||||
quote: Citere
|
||||
pinnedNote: Fastgjort opslag
|
||||
pinned: Fastgøre til profil
|
||||
you: Dig
|
||||
clickToShow: Tryk til at vise
|
||||
unblock: Blokere ikke længere
|
||||
suspend: Suspendere
|
||||
unsuspend: Suspendere ikke længere
|
||||
blockConfirm: Er du sikker på at du vil blokere denne konto?
|
||||
unblockConfirm: Er du sikker på at du vil ikke blokere denne konto endnu længere?
|
||||
suspendConfirm: Er du sikker på at du vil suspendere denne konto?
|
||||
selectAntenna: Vælg en antenne
|
||||
selectWidget: Vælg en widget
|
||||
editWidgets: Ændre widgettere
|
||||
customEmojis: Brugerdefineret emoji
|
||||
emojiName: Emoji navn
|
||||
operations: Operationer
|
||||
software: Software
|
||||
metadata: Metadata
|
||||
version: Version
|
||||
monitor: Vagt
|
||||
jobQueue: Jobkø
|
||||
statistics: Statistik
|
||||
cpuAndMemory: CPU og hukommelse
|
||||
network: Netværk
|
||||
disk: Disk
|
||||
instanceInfo: Instans information
|
||||
noThankYou: Nej tak
|
||||
noNotifications: Intet notifikationer
|
||||
addUser: Indsæt en bruger
|
||||
addInstance: Indsæt en instans
|
||||
favorite: Indsæt til bogmærker
|
||||
favorites: Bogmærker
|
||||
showMore: Vis mere
|
||||
showLess: Luk
|
||||
youGotNewFollower: følgte dig
|
||||
followRequestAccepted: Følgeanmodning accepteret
|
||||
mention: Nævne
|
||||
mentions: Nævnene
|
||||
directNotes: Direkt beskeder
|
||||
importAndExport: Importere/Eksporter data
|
||||
download: Download
|
||||
exportRequested: Du har bedt om en eksport. Det vil tage noget tid. Den vil blive
|
||||
tilsæt til din Drev når den er færdig.
|
||||
importRequested: Du har bedt om en eksport. Det vil tage noget tid.
|
||||
note: Opslag
|
||||
notes: Opslage
|
||||
following: Følger
|
||||
followers: Følgere
|
||||
followsYou: Følger dig
|
||||
createList: Skab en list
|
||||
manageLists: Administrere lister
|
||||
error: Fejl
|
||||
somethingHappened: En fejl har opstået
|
||||
retry: Gentage
|
||||
pageLoadError: En fejl har opstået ved indlæsning af siden.
|
||||
pageLoadErrorDescription: Dette er normalt på grund af netværksproblemer eller din
|
||||
browser's cache. Prøv at ryd cachen og så gentage efter et styk tid.
|
||||
serverIsDead: Serveren svarer ikke. Vær sød at vente et styk tid og prøv igen.
|
||||
editWidgetsExit: Færdig
|
||||
headlineMisskey: En åben-kildekode, decentraliseret social-media platform som er frit
|
||||
forevigt! 🚀
|
||||
introMisskey: Velkommen! Firefish er en åbent-kildekode, decentraliseret social-media
|
||||
platform som er frit forevigt!🚀
|
||||
enableEmojiReactions: Aktivere emoji reaktioner
|
||||
unsuspendConfirm: Er du sikker på at du vil ikke suspendere denne konto endnu længere?
|
||||
selectList: Vælg en list
|
||||
showEmojisInReactionNotifications: Vis emoji i reaktion notifikationer
|
||||
attachCancel: Fjern tilknyttelse
|
||||
markAsSensitive: Markere som NSFW
|
||||
unmarkAsSensitive: Markere ikke som NSFW længere
|
||||
enterFileName: Indtast filnavn
|
||||
mute: Nedtone
|
||||
unmute: Nedtone ikke længere
|
||||
renoteMute: Nedtone forstærkninger
|
||||
renoteUnmute: Nedtone forstærkninger ikke længere
|
||||
block: Blokere
|
||||
cacheRemoteFiles: Cachere fremmed filer
|
||||
flagAsBotDescription: Aktivere denne valgmulighed hvis denne konto er kontrolleret
|
||||
af en komputerprogram. Hvis den et tændt så vil det signalere til andre udviklere
|
||||
som arbejder på komputer-kontrolleret social-media kontoer og det vil også adjustere
|
||||
Firefish's indresystemer til at behandle denne konto som en robot.
|
||||
flagAsCat: Er du en kat? 😺
|
||||
flagSpeakAsCat: Tale som en kat
|
||||
emojiUrl: Emoji URL
|
||||
addEmoji: Tilsæt
|
||||
settingGuide: Anbefalet indstillinger
|
||||
flagSpeakAsCatDescription: Din opslage vil blive nyaniferet når du er i kat-mode
|
||||
autoAcceptFollowed: Automatisk godkende følgeanmodninger fra brugere som du selv følger
|
||||
addAccount: Tilsæt konto
|
||||
wallpaper: Baggrund
|
||||
setWallpaper: Sæt baggrund
|
||||
removeWallpaper: Fjern baggrund
|
||||
host: Host
|
||||
selectUser: Vælg en bruger
|
||||
searchWith: 'Søge: {q}'
|
||||
youHaveNoLists: Du har ingen liste
|
||||
followConfirm: Er du sikker på at du vil gerne følge {name}?
|
||||
proxyAccount: Proxykonto
|
||||
proxyAccountDescription: En proxykonto er en konto som virker som en fremmed følger
|
||||
for bruger under særlige konditioner. For eksempel, når en bruger tilsætter en fjernbruger
|
||||
til denne list, vil denne fjernbruger's aktivitet ikke blive leveret til den instans
|
||||
hvis ingen lokalebruger følger fjernbrugeren, så denne proxykonto vil følge den
|
||||
istedetfor.
|
||||
instances: Instanser
|
||||
registeredAt: Registreret på
|
||||
latestRequestSentAt: Sidste anmodning sendt
|
||||
latestRequestReceivedAt: Sidste anmodning modtaget
|
||||
selectInstance: Vælg en instans
|
||||
recipient: Recipient(er)
|
||||
annotation: Kommentarer
|
||||
federation: Føderation
|
||||
latestStatus: Senest status
|
||||
storageUsage: Opbevaringspladsbrug
|
||||
charts: Grafer
|
||||
perHour: Hver time
|
||||
perDay: Hver dag
|
||||
stopActivityDelivery: Stop med at sende aktiviteter
|
||||
blockThisInstance: Blokere denne instans
|
||||
muteAndBlock: Mutes og blokeringer
|
||||
mutedUsers: Mutede brugere
|
||||
newer: nyere
|
||||
older: ældre
|
||||
silencedInstances: Nedtonede servere
|
||||
clearQueue: Ryd kø
|
||||
clearQueueConfirmTitle: Er du sikker på, at du ønsker at rydde køen?
|
||||
clearCachedFiles: Ryd cache
|
||||
clearCachedFilesConfirm: Er du sikker på, at du ønsker at slette alle cachede eksterne
|
||||
filer?
|
||||
blockedInstances: Blokerede servere
|
||||
blockedInstancesDescription: Listen af navne på servere, du ønsker at blokere. Servere
|
||||
på listen vil ikke længere kunne kommunikere med denne server.
|
||||
hiddenTags: Skjulte hashtags
|
||||
clearQueueConfirmText: De indlæg i denne kø, der ikke allerede er leveret, vil ikke
|
||||
blive federeret. Denne operation er almindeligvis ikke påkrævet.
|
||||
jumpToPrevious: Spring til tidligere
|
||||
cw: Advarsel om indhold
|
2152
locales/de-DE.yml
Normal file
2152
locales/de-DE.yml
Normal file
File diff suppressed because it is too large
Load diff
819
locales/el-GR.yml
Normal file
819
locales/el-GR.yml
Normal file
|
@ -0,0 +1,819 @@
|
|||
_lang_: "Ελληνικά"
|
||||
monthAndDay: "{day}/{month}"
|
||||
search: "Αναζήτηση"
|
||||
notifications: "Ειδοποιήσεις"
|
||||
username: "Όνομα μέλους"
|
||||
password: "Κωδικός πρόσβασης"
|
||||
forgotPassword: "Ξέχασα τον κωδικό πρόσβασης"
|
||||
fetchingAsApObject: "Άντληση από το Fediverse"
|
||||
ok: "Εντάξει"
|
||||
gotIt: "Τό'πιασα!"
|
||||
cancel: "Ακύρωση"
|
||||
enterUsername: "Εισαγωγή ονόματος μέλους"
|
||||
renotedBy: "Προωθήθηκε από {user}"
|
||||
noNotes: "Δεν υπάρχουν δημοσιεύσεις"
|
||||
noNotifications: "Δεν υπάρχουν ειδοποιήσεις"
|
||||
settings: "Ρυθμίσεις"
|
||||
basicSettings: "Βασικές Ρυθμίσεις"
|
||||
otherSettings: "Άλλες Ρυθμίσεις"
|
||||
openInWindow: "Άνοιγμα σε παράθυρο"
|
||||
profile: "Προφίλ"
|
||||
timeline: "Χρονολόγιο"
|
||||
noAccountDescription: "Αυτό το μέλος δεν έχει γράψει βιογραφικό ακόμη."
|
||||
login: "Σύνδεση"
|
||||
loggingIn: "Συνδέεστε"
|
||||
logout: "Αποσύνδεση"
|
||||
signup: "Εγγραφή"
|
||||
uploading: "Ανέβασμα..."
|
||||
save: "Αποθήκευση"
|
||||
users: "Μέλη"
|
||||
addUser: "Προσθήκη μέλους"
|
||||
favorite: "Προσθήκη στους σελιδοδείκτες"
|
||||
favorites: "Σελιδοδείκτες"
|
||||
unfavorite: "Αφαίρεση από τους σελιδοδείκτες"
|
||||
favorited: "Προστέθηκε στους σελιδοδείκτες."
|
||||
alreadyFavorited: "Έχει ήδη προστεθεί στους σελιδοδείκτες."
|
||||
cantFavorite: "Αδυναμία προσθήκης στους σελιδοδείκτες."
|
||||
pin: "Καρφίτσωμα στο προφίλ"
|
||||
unpin: "Ξεκαρφίτσωμα από το προφίλ"
|
||||
copyContent: "Αντιγραφή περιεχομένων"
|
||||
copyLink: "Αντιγραφή συνδέσμου"
|
||||
delete: "Διαγραφή"
|
||||
deleteAndEdit: "Διαγραφή και επεξεργασία"
|
||||
deleteAndEditConfirm: "Σίγουρα θέλετε να διαγράψετε αυτή τη δημοσίευση και να την\
|
||||
\ επεξεργαστείτε; Θα χάσετε όλες τις αντιδράσεις, προωθήσεις και απαντήσεις σε αυτήν."
|
||||
addToList: "Προσθήκη στη λίστα"
|
||||
sendMessage: "Αποστολή μηνύματος"
|
||||
copyUsername: "Αντιγραφή ονόματος μέλους"
|
||||
searchUser: "Αναζήτηση μέλους"
|
||||
reply: "Απάντηση"
|
||||
loadMore: "Φόρτωσε περισσότερα"
|
||||
showMore: "Δείξε περισσότερα"
|
||||
showLess: "Κλείσιμο"
|
||||
youGotNewFollower: "σε ακολούθησε"
|
||||
receiveFollowRequest: "Λάβατε αίτημα ακολούθησης"
|
||||
followRequestAccepted: "Το αίτημα ακολούθησης έγινε δεκτό"
|
||||
mention: "Επισήμανση"
|
||||
mentions: "Επισημάνσεις"
|
||||
directNotes: "Απευθείας μηνύματα"
|
||||
importAndExport: "Εισαγωγή/Εξαγωγή Δεδομένων"
|
||||
import: "Εισαγωγή"
|
||||
export: "Εξαγωγή"
|
||||
files: "Αρχεία"
|
||||
download: "Κατέβασμα"
|
||||
driveFileDeleteConfirm: "Θέλετε σίγουρα να διαγράψετε το αρχείο \"{name}\"; Οι δημοσιεύσεις\
|
||||
\ με αυτό το συνημμένο αρχείο επίσης θα διαγραφούν."
|
||||
unfollowConfirm: "Θέλετε σίγουρα να σταματήσετε να ακολουθείτε το μέλος {name};"
|
||||
exportRequested: "Ζητήσατε μία εξαγωγή. Αυτό μπορεί να πάρει κάποιον χρόνο. Θα προστεθεί\
|
||||
\ στον Αποθηκευτικό Χώρο σας μόλις ολοκληρωθεί."
|
||||
importRequested: "Ζητήσατε μια εισαγωγή. Αυτό μπορεί να πάρει κάποιον χρόνο."
|
||||
lists: "Λίστες"
|
||||
noLists: "Δεν έχετε λίστες"
|
||||
note: "Δημοσίευση"
|
||||
notes: "Δημοσιεύσεις"
|
||||
following: "Ακολουθεί"
|
||||
followers: "Ακολουθούν"
|
||||
followsYou: "Σε ακολουθεί"
|
||||
createList: "Δημιουργία λίστας"
|
||||
manageLists: "Διαχείριση λιστών"
|
||||
error: "Σφάλμα"
|
||||
somethingHappened: "Προέκυψε ένα σφάλμα"
|
||||
retry: "Προσπάθεια ξανά"
|
||||
pageLoadError: "Ένα σφάλμα προέκυψε φορτώνοντας τη σελίδα."
|
||||
pageLoadErrorDescription: "Αυτό κανονικά προκαλείται από σφάλματα δικτύου ή από την\
|
||||
\ προσωρινή μνήμη του προγράμματος περιήγησης. Δοκιμάστε να σβήσετε την προσωρινή\
|
||||
\ μνήμη (cache) και να δοκιμάσετε ξανά μετά από λίγο."
|
||||
serverIsDead: "Αυτός ο διακομιστής (server) δεν αποκρίνεται. Παρακαλώ περιμένετε λίγο\
|
||||
\ και δοκιμάστε ξανά."
|
||||
youShouldUpgradeClient: "Για να δείτε αυτή τη σελίδα, παρακαλώ επαναφορτώστε για να\
|
||||
\ γίνει ενημέρωση."
|
||||
enterListName: "Πληκτρολογήστε ένα όνομα για τη λίστα"
|
||||
privacy: "Ιδιωτικότητα"
|
||||
makeFollowManuallyApprove: "Τα αιτήματα ακολούθησης χρειάζονται έγκριση"
|
||||
defaultNoteVisibility: "Προεπιλεγμένη ορατότητα"
|
||||
follow: "Ακολουθήστε"
|
||||
followRequest: "Ακολουθήστε"
|
||||
followRequests: "Αιτήματα ακολούθησης"
|
||||
unfollow: "Να μην ακολουθώ"
|
||||
followRequestPending: "Το αίτημα ακολούθησης εκκρεμεί"
|
||||
enterEmoji: "Εισάγετε ένα emoji"
|
||||
renote: "Προώθηση"
|
||||
unrenote: "Αναίρεση προώθησης"
|
||||
renoted: "Προωθήθηκε."
|
||||
cantRenote: "Αυτή η δημοσίευση δεν μπορεί να προωθηθεί."
|
||||
cantReRenote: "Μία προώθηση δεν μπορεί να προωθηθεί."
|
||||
quote: "Παράθεση"
|
||||
pinnedNote: "Καρφιτσωμένη δημοσίευση"
|
||||
pinned: "Καρφίτσωμα στο προφίλ"
|
||||
you: "Εσύ"
|
||||
clickToShow: "Κάντε κλικ για εμφάνιση"
|
||||
add: "Προσθήκη"
|
||||
reaction: "Αντιδράσεις"
|
||||
reactionSetting: "Αντιδράσεις που θα εμφανίζονται στον επιλογέα"
|
||||
reactionSettingDescription2: "Σύρετε για να αλλάξετε τη σειρά, κάντε κλικ για να διαγράψετε,\
|
||||
\ πατήστε \"+\" για να προσθέσετε."
|
||||
rememberNoteVisibility: "Θυμήσου τις ρυθμίσεις ορατότητας για τις δημοσιεύσεις"
|
||||
attachCancel: "Αφαίρεση επισυναπτόμενου"
|
||||
enterFileName: "Πληκτρολογήστε όνομα αρχείου"
|
||||
mute: "Σίγαση"
|
||||
unmute: "Διακοπή σίγασης"
|
||||
block: "Μπλοκάρισμα"
|
||||
unblock: "Διακοπή μπλοκαρίσματος"
|
||||
suspend: "Αποβολή"
|
||||
unsuspend: "Διακοπή αποβολής"
|
||||
blockConfirm: "Θέλετε σίγουρα να μπλοκάρετε αυτόν τον λογαριασμό;"
|
||||
unblockConfirm: "Θέλετε σίγουρα να ξεμπλοκάρετε αυτόν τον λογαριασμό;"
|
||||
suspendConfirm: "Θέλετε σίγουρα να αποβάλετε αυτόν τον λογαριασμό;"
|
||||
unsuspendConfirm: "Θέλετε σίγουρα να άρετε την αποβολή αυτού του λογαριασμού;"
|
||||
selectList: "Επιλέξτε μια λίστα"
|
||||
selectAntenna: "Επιλέξτε μια αντένα"
|
||||
selectWidget: "Επιλέξτε ένα πρόσθετο"
|
||||
editWidgets: "Επεξεργασία πρόσθετων"
|
||||
editWidgetsExit: "Ολοκληρώθηκε"
|
||||
customEmojis: "Προσαρμοσμένα Emoji"
|
||||
emojiName: "Όνομα emoji"
|
||||
addEmoji: "Προσθήκη"
|
||||
settingGuide: "Προτεινόμενες ρυθμίσεις"
|
||||
flagAsBot: "Δήλωση αυτού του λογαριασμού ως bot"
|
||||
flagAsCat: "Είσαι γατί; \U0001F63A"
|
||||
flagShowTimelineReplies: "Εμφάνιση απαντήσεων στο χρονολόγιο"
|
||||
addAccount: "Προσθήκη λογαριασμού"
|
||||
general: "Γενικές"
|
||||
wallpaper: "Ταπετσαρία"
|
||||
setWallpaper: "Ορισμός ταπετσαρίας"
|
||||
removeWallpaper: "Αφαίρεση ταπετσαρίας"
|
||||
searchWith: "Αναζήτηση: {q}"
|
||||
youHaveNoLists: "Δεν έχετε λίστες"
|
||||
followConfirm: "Θέλετε σίγουρα να ακολουθήσετε τον λογαριασμό {name};"
|
||||
host: "Φιλοξενεί (Host)"
|
||||
selectUser: "Επιλέξτε ένα μέλος"
|
||||
recipient: "Αποδέκτης-τρια(-ες)"
|
||||
annotation: "Σχόλια"
|
||||
federation: "Ομοσπονδία"
|
||||
storageUsage: "Χρήση χώρου"
|
||||
version: "Έκδοση"
|
||||
metadata: "Μεταδεδομένα"
|
||||
network: "Δίκτυο"
|
||||
disk: "Δίσκος"
|
||||
instanceInfo: "Πληροφορίες Instance"
|
||||
statistics: "Στατιστικά"
|
||||
clearQueue: "Εκκαθάριση ουράς"
|
||||
clearQueueConfirmTitle: "Θέλετε να διαγράψετε την ουρά;"
|
||||
clearCachedFiles: "Εκκαθάριση προσωρινής μνήμης (cache)"
|
||||
done: "Ολοκληρώθηκε"
|
||||
attachFile: "Επισύναψη αρχείων"
|
||||
more: "Περισσότερα!"
|
||||
noSuchUser: "Το μέλος δεν βρέθηκε"
|
||||
announcements: "Ανακοινώσεις"
|
||||
imageUrl: "URL εικόνας"
|
||||
remove: "Διαγραφή"
|
||||
removed: "Η διαγραφή ολοκληρώθηκε επιτυχώς"
|
||||
saved: "Αποθηκεύτηκε"
|
||||
messaging: "Συνομιλία"
|
||||
upload: "Ανεβάστε"
|
||||
fromDrive: "Από τον Αποθηκευτικό Χώρο"
|
||||
fromUrl: "Από URL"
|
||||
uploadFromUrl: "Ανέβασμα από URL"
|
||||
explore: "Εξερεύνηση"
|
||||
messageRead: "Διαβάστηκε"
|
||||
startMessaging: "Ξεκινήστε μια νέα συνομιλία"
|
||||
nUsersRead: "διαβάστηκε από {n}"
|
||||
tos: "Όροι Χρήσης"
|
||||
start: "Ας αρχίσουμε"
|
||||
home: "Κεντρικό"
|
||||
activity: "Δραστηριότητα"
|
||||
images: "Εικόνες"
|
||||
birthday: "Γενέθλια"
|
||||
registeredDate: "Έγινε μέλος στις"
|
||||
location: "Τοποθεσία"
|
||||
theme: "Θέματα"
|
||||
light: "Φωτεινό"
|
||||
dark: "Σκοτεινό"
|
||||
drive: "Αποθηκευτικός Χώρος"
|
||||
fileName: "Όνομα αρχείου"
|
||||
selectFile: "Επιλέξτε ένα αρχείο"
|
||||
selectFiles: "Επιλέξτε αρχεία"
|
||||
selectFolder: "Επιλέξτε φάκελο"
|
||||
selectFolders: "Επιλέξτε φακέλους"
|
||||
renameFile: "Μετονομασία αρχείου"
|
||||
addFile: "Προσθέστε ένα αρχείο"
|
||||
emptyDrive: "Ο Αποθηκευτικός Χώρος σας είναι άδειος"
|
||||
copyUrl: "Αντιγραφή διεύθυνσης URL"
|
||||
rename: "Μετονομασία"
|
||||
avatar: "Άβαταρ"
|
||||
banner: "Εξώφυλλο"
|
||||
reload: "Ανανέωση"
|
||||
doNothing: "Αγνόηση"
|
||||
watch: "Παρακολούθηση"
|
||||
unwatch: "Διακοπή παρακολούθησης"
|
||||
accept: "Αποδοχή"
|
||||
reject: "Απόρριψη"
|
||||
normal: "Κανονικό"
|
||||
instanceName: "Όνομα instance"
|
||||
thisYear: "Έτος"
|
||||
thisMonth: "Μήνας"
|
||||
today: "Σήμερα"
|
||||
dayX: "{day}"
|
||||
pages: "Σελίδες"
|
||||
connectService: "Σύνδεση"
|
||||
disconnectService: "Αποσύνδεση"
|
||||
registration: "Εγγραφή"
|
||||
pinnedPages: "Καρφιτσωμένες Σελίδες"
|
||||
pinnedNotes: "Καρφιτσωμένες δημοσιεύσεις"
|
||||
antennas: "Αντένες"
|
||||
manageAntennas: "Διαχείριση Αντενών"
|
||||
name: "Όνομα"
|
||||
antennaSource: "Πηγή Αντένας"
|
||||
antennaKeywords: "Λέξεις-κλειδιά για παρακολούθηση"
|
||||
antennaExcludeKeywords: "Λέξεις-κλειδιά για εξαίρεση"
|
||||
notifyAntenna: "Ειδοποίηση για νέες δημοσιεύσεις"
|
||||
withFileAntenna: "Μόνο δημοσιεύσεις με αρχεία"
|
||||
caseSensitive: "Διάκριση Πεζών-Κεφαλαίων"
|
||||
popularTags: "Δημοφιλείς ετικέτες"
|
||||
userList: "Λίστες"
|
||||
about: "Σχετικά με"
|
||||
moderator: "Συντονιστής/στρια"
|
||||
moderation: "Συντονισμός"
|
||||
cacheClear: "Εκκαθάριση προσωρινής μνήμης (cache)"
|
||||
markAsReadAllNotifications: "Σημειώστε όλες τις ειδοποιήσεις ως διαβασμένες"
|
||||
group: "Ομάδα"
|
||||
groups: "Ομάδες"
|
||||
createGroup: "Δημιουργία ομάδας"
|
||||
ownedGroups: "Οι ομάδες σας"
|
||||
groupName: "Όνομα ομάδας"
|
||||
members: "Μέλη"
|
||||
transfer: "Μεταφορά"
|
||||
messagingWithUser: "Προσωπική συνομιλία"
|
||||
messagingWithGroup: "Ομαδική συνομιλία"
|
||||
title: "Τίτλος"
|
||||
text: "Κείμενο"
|
||||
enable: "Ενεργοποίηση"
|
||||
next: "Επόμενο"
|
||||
noteOf: "Δημοσίευση από {user}"
|
||||
inviteToGroup: "Πρόσκληση στην ομάδα"
|
||||
quoteAttached: "Παράθεση"
|
||||
signinRequired: "Παρακαλούμε δημιουργήστε λογαριασμό ή συνδεθείτε πριν συνεχίσετε"
|
||||
category: "Κατηγορία"
|
||||
tags: "Ετικέτες"
|
||||
createAccount: "Δημιουργία λογαριασμού"
|
||||
local: "Τοπικό"
|
||||
remote: "Απομακρυσμένο"
|
||||
total: "Σύνολο"
|
||||
appearance: "Εμφάνιση"
|
||||
accountSettings: "Ρυθμίσεις Λογαριασμού"
|
||||
sounds: "Ήχοι"
|
||||
sound: "Ήχοι"
|
||||
listen: "Ακρόαση"
|
||||
showInPage: "Εμφάνιση στη σελίδα"
|
||||
volume: "Ένταση"
|
||||
masterVolume: "Κεντρική ένταση"
|
||||
details: "Λεπτομέρειες"
|
||||
install: "Εγκαταστήστε"
|
||||
uninstall: "Απεγκατάσταση"
|
||||
manage: "Διαχείριση"
|
||||
smtpHost: "Φιλοξενεί (Host)"
|
||||
smtpUser: "Όνομα μέλους"
|
||||
smtpPass: "Κωδικός"
|
||||
notificationSetting: "Ρυθμίσεις ειδοποιήσεων"
|
||||
notificationSettingDesc: "Επιλέξτε τους τύπους ειδοποιήσεων για προβολή."
|
||||
switchUi: "Διάταξη"
|
||||
clip: "Κλιπ"
|
||||
driveFilesCount: "Αριθμός αρχείων Αποθηκευτικού Χώρου"
|
||||
driveUsage: "Χρήση Αποθηκευτικού Χώρου"
|
||||
noteFavoritesCount: "Αριθμός αγαπημένων σημειωμάτων"
|
||||
clips: "Κλιπ"
|
||||
clearCache: "Εκκαθάριση προσωρινής μνήμης"
|
||||
emailNotification: "Ειδοποιήσεις μέσω mail"
|
||||
inChannelSearch: "Αναζήτηση στο κανάλι"
|
||||
info: "Πληροφορίες"
|
||||
notRecommended: "Δεν προτείνεται"
|
||||
switchAccount: "Αλλαγή λογαριασμού"
|
||||
user: "Μέλη"
|
||||
administration: "Διαχείριση"
|
||||
switch: "Εναλλαγή"
|
||||
gallery: "Γκαλερί"
|
||||
global: "Παγκόσμιο"
|
||||
searchResult: "Αποτελέσματα αναζήτησης"
|
||||
learnMore: "Μάθετε περισσότερα"
|
||||
controlPanel: "Πίνακας ελέγχου"
|
||||
manageAccounts: "Διαχείριση Λογαριασμών"
|
||||
searchByGoogle: "Αναζήτηση"
|
||||
file: "Αρχεία"
|
||||
recommended: "Προτεινόμενα"
|
||||
cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω ανεπαρκούς Αποθηκευτικού\
|
||||
\ Χώρου."
|
||||
_email:
|
||||
_follow:
|
||||
title: "Έχετε ένα νέο ακόλουθο"
|
||||
_mfm:
|
||||
mention: "Επισήμανση"
|
||||
quote: "Παράθεση"
|
||||
emoji: "Επιπλέον emoji"
|
||||
search: "Αναζήτηση"
|
||||
_channel:
|
||||
featured: "Δημοφιλή"
|
||||
_theme:
|
||||
keys:
|
||||
panel: "Πίνακας"
|
||||
mention: "Επισήμανση"
|
||||
renote: "Κοινοποίηση σημειώματος"
|
||||
_sfx:
|
||||
note: "Σημειώματα"
|
||||
notification: "Ειδοποιήσεις"
|
||||
chat: "Συνομιλία"
|
||||
chatBg: "Συνομιλία (Παρασκήνιο)"
|
||||
antenna: "Αντένες"
|
||||
channel: "Ειδοποιήσεις καναλιών"
|
||||
_ago:
|
||||
future: "Μελλοντικό"
|
||||
justNow: "Μόλις τώρα"
|
||||
secondsAgo: "{n} δευτερόλεπτο(α) πριν"
|
||||
minutesAgo: "{n} λεπτό(ά) πριν"
|
||||
hoursAgo: "{n} ώρα(ες) πριν"
|
||||
daysAgo: "{n} μέρα(ες) πριν"
|
||||
weeksAgo: "{n} εβδομάδα(ες) πριν"
|
||||
monthsAgo: "{n} μήνα(ες) πριν"
|
||||
yearsAgo: "{n} έτος(η) πριν"
|
||||
_permissions:
|
||||
"write:drive": "Επεξεργαστείτε ή διαγράψτε τα αρχεία και τους φακέλους του Αποθηκευτικού\
|
||||
\ Χώρου σας"
|
||||
"read:favorites": "Δείτε τη λίστα με τους σελιδοδείκτες σας"
|
||||
"write:favorites": "Επεξεργαστείτε τη λίστα με τους σελιδοδείκτες σας"
|
||||
"read:messaging": "Δείτε τις συνομιλίες σας"
|
||||
"write:messaging": "Γράψτε ή διαγράψτε μηνύματα συνομιλίας"
|
||||
"read:notifications": "Δείτε τις ειδοποιήσεις σας"
|
||||
"write:notifications": "Διαχειριστείτε τις ειδοποιήσεις σας"
|
||||
"read:pages": "Δείτε τις Σελίδες σας"
|
||||
"write:pages": "Επεξεργαστείτε ή διαγράψτε τις σελίδες σας"
|
||||
"write:gallery-likes": Επεξεργασία της λίστας των αγαπημένων σας δημοσιεύσεων γκαλερί
|
||||
"read:gallery": Δείτε την γκαλερί σας
|
||||
"write:gallery": Επεξεργασία της γκαλερί σας
|
||||
"read:gallery-likes": Δείτε τη λίστα των αγαπημένων σας δημοσιεύσεων γκαλερί
|
||||
_antennaSources:
|
||||
all: "Όλα τα σημειώματα"
|
||||
homeTimeline: "Σημειώματα από μέλη που ακολουθείτε"
|
||||
users: "Σημειώματα από συγκεκριμένα μέλη"
|
||||
userList: "Σημειώματα από καθορισμένη λίστα μελών"
|
||||
userGroup: "Σημειώματα από μέλη καθορισμένης ομάδας"
|
||||
_widgets:
|
||||
profile: "Προφίλ"
|
||||
instanceInfo: "Πληροφορίες του instance"
|
||||
notifications: "Ειδοποιήσεις"
|
||||
timeline: "Χρονολόγιο"
|
||||
calendar: "Ημερολόγιο"
|
||||
trends: "Δημοφιλή"
|
||||
clock: "Ρολόι"
|
||||
activity: "Δραστηριότητα"
|
||||
photos: "Φωτογραφίες"
|
||||
digitalClock: "Ψηφιακό ρολόι"
|
||||
federation: "Ομοσπονδία"
|
||||
postForm: "Φόρμα δημοσίευσης"
|
||||
button: "Κουμπί"
|
||||
onlineUsers: "Συνδεδεμένα μέλη"
|
||||
_userList:
|
||||
chooseList: "Επιλέξτε μία λίστα"
|
||||
_cw:
|
||||
show: "Δείτε περισσότερα"
|
||||
_visibility:
|
||||
home: "Κεντρικό"
|
||||
homeDescription: "Δημοσίευση στο κεντρικό χρονολόγιο μόνο"
|
||||
followers: "Ακολουθούν"
|
||||
_profile:
|
||||
name: "Όνομα"
|
||||
username: "Όνομα μέλους"
|
||||
changeAvatar: Αλλαγή άβαταρ
|
||||
_exportOrImport:
|
||||
allNotes: "Όλα τα σημειώματα"
|
||||
followingList: "Ακολουθεί"
|
||||
muteList: "Μέλη σε σίγαση"
|
||||
blockingList: "Μπλοκαρισμένα μέλη"
|
||||
userLists: "Λίστες"
|
||||
_charts:
|
||||
federation: "Ομοσπονδία"
|
||||
_timelines:
|
||||
home: "Κεντρικό"
|
||||
local: "Τοπικό"
|
||||
social: "Κοινωνικό"
|
||||
global: "Παγκόσμιο"
|
||||
_pages:
|
||||
viewPage: "Δείτε τις Σελίδες σας"
|
||||
blocks:
|
||||
image: "Εικόνες"
|
||||
_notification:
|
||||
youGotMessagingMessageFromUser: "{name} σάς έστειλε ένα μήνυμα συνομιλίας"
|
||||
youWereFollowed: "σε ακολούθησε"
|
||||
_types:
|
||||
follow: "Νέοι ακόλουθοι"
|
||||
mention: "Επισήμανση"
|
||||
renote: "Κοινοποίηση σημειώματος"
|
||||
quote: "Παράθεση"
|
||||
reaction: "Αντιδράσεις"
|
||||
_actions:
|
||||
reply: "Απάντηση"
|
||||
renote: "Κοινοποίηση σημειώματος"
|
||||
_deck:
|
||||
widgetsIntroduction: "Παρακαλούμε επιλέξτε \"Επεξεργασία πρόσθετων\" στο μενού και\
|
||||
\ προσθέστε μαραφέτι."
|
||||
_columns:
|
||||
widgets: "Πρόσθετα"
|
||||
notifications: "Ειδοποιήσεις"
|
||||
tl: "Χρονολόγιο"
|
||||
antenna: "Αντένες"
|
||||
list: "Λίστα"
|
||||
mentions: "Επισημάνσεις"
|
||||
sensitive: Ευαίσθητο περιεχόμενο (NSFW)
|
||||
createFolder: Δημιουργία φακέλου
|
||||
uploadFromUrlDescription: Το URL του αρχείου που θέλετε να ανεβάσετε
|
||||
emptyFolder: Αυτός ο φάκελος είναι άδειος
|
||||
unableToDelete: Αδυναμία διαγραφής
|
||||
recentlyUpdatedUsers: Πρόσφατα ενεργά μέλη
|
||||
recentlyRegisteredUsers: Νέα μέλη
|
||||
exploreUsersCount: Υπάρχουν {count} μέλη
|
||||
help: Βοήθεια
|
||||
inputNewFileName: Πληκτρολογήστε ένα νέο όνομα αρχείου
|
||||
nothing: Δεν υπάρχει τίποτα να δείτε εδώ
|
||||
newNoteRecived: Υπάρχουν νέες δημοσιεύσεις
|
||||
passwordMatched: Ταιριάζει
|
||||
unmarkAsSensitive: Αναίρεση επισήμανσης ως Ευαίσθητο Περιεχόμενο (NSFW)
|
||||
blockedUsers: Μπλοκαρισμένα μέλη
|
||||
noteDeleteConfirm: Θέλετε σίγουρα να διαγράψετε αυτή τη δημοσίευση;
|
||||
preview: Προεπισκόπηση
|
||||
noCustomEmojis: Δεν υπάρχουν emoji
|
||||
tosUrl: URL Όρων Χρήσης
|
||||
monthX: '{month}'
|
||||
markAsReadAllTalkMessages: Σημειώστε όλα τα μηνύματα ως διαβασμένα
|
||||
inputMessageHere: Γράψτε εδώ το μήνυμά σας
|
||||
close: Κλείσιμο
|
||||
newMessageExists: Υπάρχουν νέα μηνύματα
|
||||
usernameInvalidFormat: Μπορείτε να χρησιμοποιήσετε κεφαλαία και μικρά γράμματα, αριθμούς,
|
||||
και κάτω παύλες.
|
||||
tooShort: Πολύ σύντομο
|
||||
passwordNotMatched: Δεν ταιριάζει
|
||||
existingAccount: Υπάρχων λογαριασμός
|
||||
deleteAll: Διαγραφή όλων
|
||||
chooseEmoji: Επιλέξτε ένα emoji
|
||||
sort: Ταξινόμηση
|
||||
descendingOrder: Φθίνουσα
|
||||
deleteAllFiles: Διαγραφή όλων των αρχείων
|
||||
userSuspended: Αυτό το μέλος έχει αποβληθεί.
|
||||
menu: Μενού
|
||||
divider: Χώρισμα
|
||||
deletedNote: Διαγραμμένη δημοσίευση
|
||||
useCw: Απόκρυψη περιεχομένου
|
||||
description: Περιγραφή
|
||||
width: Πλάτος
|
||||
disableAll: Απενεργοποίηση όλων
|
||||
notificationType: Τύπος ειδοποίησης
|
||||
wordMute: Σίγαση λέξεων
|
||||
userSaysSomething: '{name} είπε κάτι'
|
||||
metrics: Μετρήσεις
|
||||
overview: Γενική εικόνα
|
||||
database: Βάση δεδομένων
|
||||
channel: Κανάλια
|
||||
other: Άλλα
|
||||
abuseReports: Αναφορές
|
||||
reportAbuse: Αναφορά
|
||||
unclip: Ακύρωση κλιπ
|
||||
public: Δημόσιο
|
||||
renotedCount: Αριθμός προωθήσεων που ελήφθησαν
|
||||
alwaysMarkSensitive: Επισήμανση ως ευαίσθητο περιεχόμενο (NSFW) ως προεπιλογή
|
||||
markAllAsRead: Σημειώστε τα όλα ως διαβασμένα
|
||||
_gallery:
|
||||
like: Μου αρέσει
|
||||
liked: Αγαπημένες δημοσιεύσεις
|
||||
my: Η Γκαλερί μου
|
||||
unlike: Δεν μου αρέσει
|
||||
showOnRemote: Δείτε στο απομακρυσμένο instance
|
||||
perDay: Ανά Ημέρα
|
||||
software: Λογισμικό
|
||||
cpuAndMemory: CPU και Μνήμη
|
||||
noUsers: Δεν υπάρχουν μέλη
|
||||
processing: Επεξεργασία
|
||||
changePassword: Αλλαγή κωδικού
|
||||
security: Ασφάλεια
|
||||
featured: Προτεινόμενα
|
||||
keepOriginalUploading: Διατήρηση πρωτότυπης εικόνας
|
||||
manageGroups: Διαχείριση ομάδων
|
||||
deleteFolder: Διαγραφή φακέλου
|
||||
nsfw: Ευαίσθητο περιεχόμενο (NSFW)
|
||||
nUsersMentioned: Έχει αναφερθεί από {n} μέλη
|
||||
notFound: Δεν βρέθηκε
|
||||
markAsReadAllUnreadNotes: Σημειώστε όλες τις δημοσιεύσεις ως διαβασμένες
|
||||
invites: Προσκλήσεις
|
||||
quoteQuestion: Να προστεθεί ως Παράθεση;
|
||||
noMessagesYet: Δεν υπάρχουν μηνύματα ακόμη
|
||||
onlyOneFileCanBeAttached: Μπορείτε να επισυνάψετε μόνο ένα αρχείο σε ένα μήνυμα
|
||||
tooLong: Υπερβολικά μακροσκελές
|
||||
or: Ή
|
||||
language: Γλώσσα
|
||||
groupInvited: Προσκληθήκατε σε μία ομάδα
|
||||
ascendingOrder: Αύξουσα
|
||||
visibility: Ορατότητα
|
||||
invisibleNote: Αόρατη δημοσίευση
|
||||
enableInfiniteScroll: Αυτόματη φόρτωση περισσοτέρων
|
||||
poll: Ψηφοφορία
|
||||
enablePlayer: Άνοιγμα προβολής βίντεο
|
||||
large: Μεγάλο
|
||||
medium: Μεσαίο
|
||||
small: Μικρό
|
||||
postToGallery: Δημιουργία νέας δημοσίευσης γκαλερί
|
||||
reloadConfirm: Θα θέλατε να ανανεώσετε το χρονολόγιο;
|
||||
enableAll: Ενεργοποίηση όλων
|
||||
permission: Εξουσιοδοτήσεις
|
||||
sample: Δείγμα
|
||||
copy: Αντιγραφή
|
||||
display: Προβολή
|
||||
send: Αποστολή
|
||||
behavior: Συμπεριφορά
|
||||
useGlobalSetting: Χρήση παγκόσμιων ρυθμίσεων
|
||||
abuseMarkAsResolved: Επισήμανση της αναφοράς ως επιλυμένης
|
||||
openInNewTab: Άνοιγμα σε νέα καρτέλα
|
||||
_sensitiveMediaDetection:
|
||||
setSensitiveFlagAutomatically: Επισήμανση ως ευαίσθητο περιεχόμενο (NSFW)
|
||||
defaultNavigationBehaviour: Προεπιλεγμένη συμπεριφορά περιήγησης
|
||||
system: Σύστημα
|
||||
createNew: Δημιουργία νέου
|
||||
createNewClip: Δημιουργία νέου κλιπ
|
||||
repliesCount: Αριθμός απεσταλμένων απαντήσεων
|
||||
optional: Προαιρετικό
|
||||
renotesCount: Αριθμός προωθήσεων σε δημοσιεύσεις άλλων
|
||||
addItem: Προσθήκη αντικειμένου
|
||||
disablePlayer: Κλείσιμο προβολής βίντεο
|
||||
describeFile: Προσθήκη περιγραφής
|
||||
enterFileDescription: Πληκτρολογήστε περιγραφή
|
||||
author: Συντάκτης/τρια
|
||||
setMultipleBySeparatingWithSpace: Διαχωρίστε πολλαπλές καταχωρήσεις με κενά.
|
||||
random: Τυχαίο
|
||||
accountInfo: Πληροφορίες Λογαριασμού
|
||||
notesCount: Αριθμός δημοσιεύσεων
|
||||
repliedCount: Αριθμός απαντήσεων που ελήφθησαν
|
||||
flagAsCatDescription: Θα έχεις γατοαυτιά και θα μιλάς σαν γατί!
|
||||
muteAndBlock: Σιγάσεις και Μπλοκαρίσματα
|
||||
mutedUsers: Σιγασμένα μέλη
|
||||
editProfile: Επεξεργασία προφίλ
|
||||
pinLimitExceeded: Δεν μπορείτε να καρφιτσώσετε άλλες δημοσιεύσεις
|
||||
currentPassword: Τρέχων κωδικός
|
||||
newPassword: Νέος κωδικός
|
||||
newPasswordRetype: Ξαναπληκτρολογήστε τον νέο κωδικό
|
||||
notesAndReplies: Δημοσιεύσεις και απαντήσεις
|
||||
popularUsers: Δημοφιλή μέλη
|
||||
share: Κοινοποίηση
|
||||
retype: Πληκτρολογήστε ξανά
|
||||
invitations: Προσκλήσεις
|
||||
available: Διαθέσιμο
|
||||
unavailable: Μη διαθέσιμο
|
||||
youHaveNoGroups: Δεν έχετε ομάδες
|
||||
doing: Επεξεργασία...
|
||||
yourAccountSuspendedTitle: Αυτός ο λογαριασμός έχει αποβληθεί
|
||||
leaveConfirm: Υπάρχουν αλλαγές που δεν έχουν σωθεί. Θέλετε να τις απορρίψετε;
|
||||
height: Ύψος
|
||||
edit: Επεξεργασία
|
||||
headlineMisskey: Μία ανοιχτού λογισμικού, αποκεντρωμένη πλατφόρμα κοινωνικής δικτύωσης
|
||||
που θα είναι για πάντα ελεύθερη! 🚀
|
||||
introMisskey: Καλώς ήρθατε! Το Firefish είναι μία ανοιχτού λογισμικού, αποκεντρωμένη
|
||||
πλατφόρμα κοινωνικής δικτύωσης που θα είναι για πάντα ελεύθερη! 🚀
|
||||
markAsSensitive: Επισήμανση ως Ευαίσθητο Περιεχόμενο (NSFW)
|
||||
autoAcceptFollowed: Αυτόματη έγκριση αιτημάτων ακολούθησης από λογαριασμούς που ακολουθείτε
|
||||
loginFailed: Αποτυχία σύνδεσης
|
||||
accountMoved: 'Έχει μεταφερθεί σε νέο λογαριασμό:'
|
||||
perHour: Ανά Ώρα
|
||||
remoteUserCaution: Οι πληροφορίες από απομακρυσμένους λογαριασμούς μπορεί να είναι
|
||||
ατελείς.
|
||||
folderName: Όνομα φακέλου
|
||||
renameFolder: Μετονομασία φακέλου
|
||||
recentUsed: Χρησιμοποιήθηκαν πρόσφατα
|
||||
deleteAllFilesConfirm: Σίγουρα θέλετε να διαγράψετε όλα τα αρχεία;
|
||||
removeAllFollowing: Διακοπή ακολούθησης όλων των ακολουθούμενων μελών
|
||||
userSilenced: Αυτό το μέλος είναι υπό σιώπηση.
|
||||
makeActive: Ενεργοποίηση
|
||||
create: Δημιουργία
|
||||
reportAbuseOf: Αναφορά {name}
|
||||
cacheRemoteFilesDescription: Όταν αυτή η ρύθμιση είναι απενεργοποιημένη, τα απομακρυσμένα
|
||||
αρχεία φορτώνονται απευθείας από το απομακρυσμένο instance. Η απενεργοποίηση θα
|
||||
μειώσει τη χρήση του δίσκου σας, αλλά θα αυξήσει την κίνηση δεδομένων, καθώς δεν
|
||||
θα δημιουργούνται σμικρύνσεις αρχείων (thumbnails).
|
||||
registeredAt: Εγγράφηκε στις
|
||||
latestStatus: Τελευταία κατάσταση
|
||||
charts: Πίνακες
|
||||
stopActivityDelivery: Σταμάτα να στέλνεις δραστηριότητες
|
||||
operations: Λειτουργίες
|
||||
monitor: Παρακολούθηση
|
||||
jobQueue: Ουρά εργασιών
|
||||
blockedInstances: Μπλοκαρισμένα Instances
|
||||
blockedInstancesDescription: Παραθέστε τις διευθύνσεις (hostnames) των instances που
|
||||
θέλετε να μπλοκάρετε. Τα παρακάτω instances δεν θα μπορούν πλέον να επικοινωνούν
|
||||
με αυτό το instance.
|
||||
intro: Η εγκατάσταση του Firefish τελείωσε! Παρακαλώ δημιουργήστε ένα μέλος διαχειριστή/στρια.
|
||||
noThankYou: Όχι, ευχαριστώ
|
||||
addInstance: Προσθήκη instance
|
||||
renoteMute: Σίγαση προωθήσεων
|
||||
emojiUrl: Διεύθυνση emoji (URL)
|
||||
cacheRemoteFiles: Προσωρινή αποθήκευση απομακρυσμένων αρχείων
|
||||
flagSpeakAsCat: Να μιλάς σαν γατί
|
||||
flagSpeakAsCatDescription: Οι δημοσιεύσεις σου θα nyaοποιούνται όταν είσαι γατί
|
||||
selectInstance: Επιλέξτε ένα instance
|
||||
latestRequestSentAt: Τελευταίο αίτημα στάλθηκε
|
||||
hiddenTags: Κρυμμένες Ετικέτες (Hashtags)
|
||||
noInstances: Δεν υπάρχουν instances
|
||||
renoteUnmute: Διακοπή σίγασης προωθήσεων
|
||||
flagAsBotDescription: Ενεργοποιήστε αυτή την επιλογή αν αυτός ο λογαριασμός ελέγχεται
|
||||
από ένα πρόγραμμα. Αν ενεργοποιηθεί, θα λειτουργεί σαν σημάδι για τους προγραμματιστές,
|
||||
ώστε να αποφύγουν ατέρμονη αλληλεπίδραση με άλλα bots και για να ρυθμίσει τα εσωτερικά
|
||||
συστήματα του Firefish ώστε να αντιμετωπίζουν αυτόν τον λογαριασμό ως bot.
|
||||
flagShowTimelineRepliesDescription: Εμφάνιση απαντήσεων μελών σε δημοσιεύσεις άλλων
|
||||
μελών στο χρονολόγιο.
|
||||
latestRequestReceivedAt: Τελευταίο αίτημα ελήφθη
|
||||
blockThisInstance: Μπλοκάρισμα αυτού του instance
|
||||
clearQueueConfirmText: Τυχόν δημοσιεύσεις στην ουρά που δεν έχουν αποσταλεί δεν θα
|
||||
ομοσπονδοποιηθούν. Συνήθως αυτή η λειτουργία δεν χρειάζεται.
|
||||
clearCachedFilesConfirm: Σίγουρα θέλετε να διαγράψετε όλα τα προσωρινά αποθηκευμένα
|
||||
απομακρυσμένα αρχεία;
|
||||
default: Προεπιλεγμένο
|
||||
defaultValueIs: 'Προεπιλεγμένο: {value}'
|
||||
noJobs: Δεν υπάρχουν εργασίες (jobs)
|
||||
federating: Ομοσπονδοποιείται
|
||||
blocked: Μπλοκαρισμένο
|
||||
suspended: Σε αποβολή
|
||||
instanceFollowing: Ακολουθεί στο instance
|
||||
instanceFollowers: Ακόλουθοι του instance
|
||||
instanceUsers: Μέλη αυτού του instance
|
||||
retypedNotMatch: Οι καταχωρήσεις δεν ταιριάζουν.
|
||||
usernameOrUserId: Όνομα μέλους ή ταυτότητα μέλους (id)
|
||||
removeAreYouSure: Θέλετε σίγουρα να αφαιρέσετε το "{x}";
|
||||
deleteAreYouSure: Θέλετε σίγουρα να διαγράψετε το "{x}";
|
||||
resetAreYouSure: Σίγουρα επανεκκίνηση;
|
||||
uploadFromUrlMayTakeTime: Ίσως πάρει λίγο χρόνο μέχρι το ανέβασμα να ολοκληρωθεί.
|
||||
noMoreHistory: Δεν υπάρχει περαιτέρω ιστορικό
|
||||
agreeTo: Συμφωνώ στο {0}
|
||||
yearsOld: '{age} ετών'
|
||||
themeForDarkMode: Θέμα για τη Σκοτεινή Λειτουργία
|
||||
syncDeviceDarkMode: Συγχρονισμός της Σκοτεινής Λειτουργίας με τις ρυθμίσεις της συσκευής
|
||||
σας
|
||||
inputNewDescription: Προσθέστε νέα περιγραφή
|
||||
whenServerDisconnected: Όταν χάνεται η σύνδεση στον σέρβερ
|
||||
disconnectedFromServer: Η σύνδεση στον σέρβερ έχει χαθεί
|
||||
instanceDescription: Περιγραφή instance
|
||||
maintainerEmail: Διεύθυνση email προγραμματιστή/στριας
|
||||
yearX: '{year}'
|
||||
enableGlobalTimeline: Ενεργοποίηση παγκόσμιου χρονολογίου
|
||||
enableLocalTimeline: Ενεργοποίηση τοπικού χρονολογίου
|
||||
enableRegistration: Ενεργοποίηση εγγραφής νέων μελών
|
||||
invite: Πρόσκληση
|
||||
disablingTimelinesInfo: Οι Διαχειρίστριες-ες και οι Συντονιστές-στριες θα έχουν πάντα
|
||||
πρόσβαση σε όλα τα χρονολόγια, ακόμα κι αν δεν είναι ενεργοποιημένα.
|
||||
inMb: Σε megabytes
|
||||
iconUrl: Διεύθυνση URL εικονιδίου
|
||||
bannerUrl: Διεύθυνση URL εικόνας Εξώφυλλου
|
||||
pinnedUsers: Καρφιτσωμένα μέλη
|
||||
hcaptchaSiteKey: Κλειδί του site
|
||||
recaptcha: Προστασία reCAPTCHA
|
||||
enableServiceworker: Ενεργοποίηση Ειδοποιήσεων Push για τον browser σας
|
||||
recentlyDiscoveredUsers: Μέλη που ανακαλύφθηκαν πρόσφατα
|
||||
twoStepAuthentication: Επαλήθευση δύο παραγόντων
|
||||
securityKey: Κλειδί ασφάλειας
|
||||
registerSecurityKey: Καταχωρήστε ένα κλειδί ασφάλειας
|
||||
resetPassword: Επαναφορά κωδικού
|
||||
newPasswordIs: Ο νέος κωδικός είναι "{password}"
|
||||
uploadFolder: Προεπιλεγμένος φάκελος για ανέβασμα αρχείων
|
||||
joinedGroups: Οι ομάδες που είστε μέλος
|
||||
checking: Έλεγχος...
|
||||
invitationCode: Κωδικός πρόσκλησης
|
||||
normalPassword: Μέτριος κωδικός
|
||||
weakPassword: Αδύναμος κωδικός
|
||||
strongPassword: Δυνατός κωδικός
|
||||
signinWith: Συνδεθείτε με {x}
|
||||
tapSecurityKey: Βάλτε το κλειδί ασφάλειας
|
||||
signinFailed: Αδυναμία σύνδεσης. Το όνομα μέλους ή ο κωδικός είναι λάθος.
|
||||
aboutX: Σχετικά με {x}
|
||||
useOsNativeEmojis: Χρήση των Emoji του λειτουργικού συστήματος
|
||||
uiLanguage: Γλώσσα διεπαφής
|
||||
disableDrawer: Να μη χρησιμοποιούνται μενού σε στιλ συρταριού
|
||||
noHistory: Δεν υπάρχει διαθέσιμο ιστορικό
|
||||
joinOrCreateGroup: Λάβετε πρόσκληση για μία ομάδα ή δημιουργήστε τη δική σας.
|
||||
docSource: Πηγή αυτού του εγγράφου
|
||||
regenerate: Επαναδημιουργία
|
||||
fontSize: Μέγεθος γραμματοσειράς
|
||||
noFollowRequests: Δεν έχετε αιτήματα ακολούθησης σε αναμονή
|
||||
dashboard: Ταμπλό
|
||||
clientSettings: Ρυθμίσεις διεπαφής
|
||||
numberOfDays: Αριθμός ημερών
|
||||
hideThisNote: Απόκρυψη αυτής της δημοσίευσης
|
||||
showFeaturedNotesInTimeline: Εμφάνιση προτεινόμενων δημοσιεύσεων στα χρονολόγια
|
||||
objectStorage: Αποθήκευση Object Storage
|
||||
useObjectStorage: Χρήση object storage
|
||||
objectStorageBucket: ''
|
||||
showFixedPostForm: Εμφάνιση της φόρμας δημοσίευσης στο πάνω μέρος των χρονολογίων
|
||||
none: Κανένα
|
||||
unableToProcess: Η επιχείρηση ήταν αδύνατο να ολοκληρωθεί
|
||||
installedApps: Εφαρμογές με εξουσιοδότηση
|
||||
state: Κατάσταση
|
||||
installedDate: Εξουσιοδοτήθηκε στις
|
||||
lastUsedDate: Χρησιμοποιήθηκε τελευταία φορά στις
|
||||
scratchpadDescription: Το σημειωματάριο παρέχει ένα περιβάλλον για πειραματισμό με
|
||||
AiScript. Σε αυτό μπορείτε να γράψετε, να εκτελέσετε, και να δοκιμάσετε τα αποτελέσματα
|
||||
της αλληλεπίδρασης του AiScript με το Firefish.
|
||||
scratchpad: Σημειωματάριο
|
||||
output: Αποτέλεσμα
|
||||
updateRemoteUser: Ανανέωση πληροφοριών απομακρυσμένου μέλους
|
||||
disablePagesScript: Απενεργοποίηση του AiScript στις Σελίδες
|
||||
removeAllFollowingDescription: Η εκτέλεση θα διακόψη την ακολούθηση όλων των μελών
|
||||
από {host}. Παρακαλούμε εκτελέστε το αν το instance π.χ. δεν υπάρχει πια.
|
||||
caption: Αυτόματη Περιγραφή
|
||||
all: Όλα
|
||||
subscribing: Εγγραφή σε συνδρομή
|
||||
publishing: Δημοσιεύεται
|
||||
notResponding: Δεν αποκρίνεται
|
||||
keepOriginalUploadingDescription: Αποθηκεύει το πρωτότυπο αρχείο όπως είναι. Αν απενεργοποιηθεί,
|
||||
μία έκδοση για προβολή στο ίντερνετ θα δημιουργηθεί κατά το ανέβασμα.
|
||||
lookup: Αναζήτηση
|
||||
lightThemes: Φωτεινά θέματα
|
||||
darkThemes: Σκοτεινά θέματα
|
||||
inputNewFolderName: Πληκτρολογήστε ένα νέο όνομα φακέλου
|
||||
hasChildFilesOrFolders: Εφόσον αυτός ο φάκελος δεν είναι άδειος, δεν μπορεί να διαγραφεί.
|
||||
integration: Ενσωματώσεις
|
||||
enableRecommendedTimeline: Ενεργοποίηση χρονολογίου προτεινόμενων
|
||||
driveCapacityPerLocalAccount: Μέγεθος Αποθηκευτικού Χώρου ανά τοπικό μέλος
|
||||
driveCapacityPerRemoteAccount: Μέγεθος Αποθηκευτικού Χώρου ανά απομακρυσμένο μέλος
|
||||
basicInfo: Βασικές πληροφορίες
|
||||
pinnedClipId: Ταυτότητα (id) του κλιπ για καρφίτσωμα
|
||||
hcaptcha: Προστασία hCaptcha
|
||||
enableHcaptcha: Ενεργοποίηση hCaptcha
|
||||
hcaptchaSecretKey: Μυστικό κλειδί
|
||||
enableRecaptcha: Ενεργοποίηση reCAPTCHA
|
||||
recaptchaSiteKey: Κλειδί του site
|
||||
recaptchaSecretKey: Μυστικό κλειδί
|
||||
antennaKeywordsDescription: Διαχωρίστε με κενά για συνθήκη ΚΑΙ ή με αλλαγή γραμμής
|
||||
για συνθήκη Ή.
|
||||
antennaUsersDescription: Παραθέστε ένα όνομα μέλους ανά γραμμή
|
||||
antennaInstancesDescription: Παραθέστε ένα instance host ανά γραμμή
|
||||
withReplies: Να περιλαμβάνονται οι απαντήσεις
|
||||
withFiles: Να περιλαμβάνουν αρχεία
|
||||
silence: Σιώπηση
|
||||
silenceConfirm: Θέλετε σίγουρα να σιωπήσετε αυτό το μέλος;
|
||||
unsilenceConfirm: Σίγουρα θέλετε να αναιρέσετε τη σιώπηση αυτού του μέλους;
|
||||
securityKeyName: Όνομα κλειδιού
|
||||
lastUsed: Τελευταία χρήση
|
||||
unregister: Απεγγραφή
|
||||
notFoundDescription: Δεν ήταν δυνατό να βρεθεί σελίδα που να ανταποκρίνεται σε αυτή
|
||||
τη διεύθυνση URL.
|
||||
signinHistory: Ιστορικό συνδέσεων
|
||||
disableAnimatedMfm: Απενεργοποίηση του MFM με κίνηση
|
||||
dayOverDayChanges: Αλλαγές την τελευταία ημέρα
|
||||
promotion: Προμοταρισμένα
|
||||
promote: Προμοτάρισμα
|
||||
squareAvatars: Εμφάνιση τετραγωνισμένων άβαταρ
|
||||
aboutFirefish: Σχετικά με το Firefish
|
||||
maintainerName: Προγραμματιστής/στρια
|
||||
uploadFromUrlRequested: Το ανέβασμα ζητήθηκε
|
||||
themeForLightMode: Θέμα για τη Φωτεινή Λειτουργία
|
||||
circularReferenceFolder: Ο φάκελος του προορισμού είναι υποφάκελος του φακέλου που
|
||||
θέλετε να μετακινήσετε.
|
||||
backgroundImageUrl: Διεύθυνση URL εικόνας φόντου
|
||||
pinnedUsersDescription: Παραθέστε τα ονόματα μελών που θα είναι καρφιτσωμένα στην
|
||||
καρτέλα "Εξερεύνηση" χωρίζοντάς τα με αλλαγή γραμμής.
|
||||
openImageInNewTab: Άνοιγμα εικόνων σε νέα καρτέλα
|
||||
weekOverWeekChanges: Αλλαγές την τελευταία εβδομάδα
|
||||
exploreFediverse: Εξερευνήστε το Fediverse
|
||||
unsilence: Αναίρεση σιώπησης
|
||||
administrator: Διαχειριστής/στρια
|
||||
passwordLessLogin: Σύνδεση χωρίς κωδικό
|
||||
reduceUiAnimation: Ελάττωση των κινούμενων εικόνων
|
||||
serviceworkerInfo: Πρέπει να είναι ενεργοποιημένο για ειδοποιήσεις push.
|
||||
expandTweet: Διεύρυνση τουιτ
|
||||
themeEditor: Επεξεργασία θεμάτων
|
||||
deck: Ντεκ
|
||||
undeck: Έξοδος από το Ντεκ
|
||||
useFullReactionPicker: Χρήση επιλογέα αντιδράσεων πλήρους μεγέθους
|
||||
tokenRequested: Παροχή πρόσβασης στον λογαριασμό
|
||||
emailServer: Σέρβερ email
|
||||
enableEmail: Ενεργοποίηση του email distribution
|
||||
emailAddress: Διεύθυνση email
|
||||
emailConfigInfo: Χρησιμοποιείται για επιβεβαίωση του email σας κατά την εγγραφή ή
|
||||
αν ξεχάσετε τον κωδικό σας
|
||||
regenerateLoginToken: Επαναδημιουργία token σύνδεσης
|
||||
fileIdOrUrl: Ταυτότητα αρχείου (ID) ή διεύθυνση URL
|
||||
typingUsers: '{users} πληκτρολογεί'
|
||||
yourAccountSuspendedDescription: Αυτός ο λογαριασμός έχει αποβληθεί λόγω μη συμμόρφωσης
|
||||
με τους κανόνες του σέρβερ ή κάτι παρόμοιο. Επικοινωνήστε με τον διαχειριστή/στρια
|
||||
αν θα θέλατε έναν πιο λεπτομερή λόγο. Παρακαλούμε μη δημιουργήσετε νέο λογαριασμό.
|
||||
inboxUrl: Διεύθυνση URL των Εισερχομένων
|
||||
generateAccessToken: Δημιουργία token πρόσβασης
|
||||
emptyToDisableSmtpAuth: Αφήστε το όνομα μέλους και τον κωδικό άδεια για να απενεργοποιήσετε
|
||||
την επαλήθευση SMTP
|
||||
instanceMute: Σιγάσεις instance
|
||||
userSaysSomethingReason: '{name} είπε {reason}'
|
||||
logs: Αρχεία καταγραφής
|
||||
abuseReported: Η αναφορά σας στάλθηκε. Ευχαριστούμε πολύ.
|
||||
reporter: Έκανε την αναφορά
|
||||
reporteeOrigin: Καταγωγή αναφερόμενου λογαριασμού
|
||||
reporterOrigin: Καταγωγή λογαριασμού που έκανε την αναφορά
|
||||
forwardReport: Προώθηση της αναφοράς στο απομακρυσμένο instance
|
||||
openInSideView: Άνοιγμα σε προβολή παράθεσης
|
||||
delayed: Με καθυστέρηση
|
||||
useGlobalSettingDesc: Αν ενεργοποιηθεί, οι ρυθμίσεις ειδοποιήσεων του λογαριασμού
|
||||
σας θα χρησιμοποιηθούν. Αν απενεργοποιηθεί, μπορούν να γίνουν ανεξάρτητες ρυθμίσεις.
|
||||
fillAbuseReportDescription: Παρακαλούμε συμπληρώστε λεπτομέρειες σχετικά με αυτή την
|
||||
αναφορά. Αν πρόκειται για συγκεκριμένη δημοσίευση, παρακαλούμε συμπεριλάβετε τη
|
||||
διεύθυνση URL της δημοσίευσης.
|
||||
forwardReportIsAnonymous: Αντί για τον λογαριασμό σας, μία ανώνυμη αναφορά από λογαριασμό
|
||||
του συστήματος θα εμφανιστεί στο απομακρυσμένο instance.
|
2111
locales/en-US.yml
Normal file
2111
locales/en-US.yml
Normal file
File diff suppressed because it is too large
Load diff
1943
locales/es-ES.yml
Normal file
1943
locales/es-ES.yml
Normal file
File diff suppressed because it is too large
Load diff
970
locales/fi.yml
Normal file
970
locales/fi.yml
Normal file
|
@ -0,0 +1,970 @@
|
|||
_lang_: "Suomi"
|
||||
username: Käyttäjänimi
|
||||
fetchingAsApObject: Hae Fedeversestä
|
||||
gotIt: Selvä!
|
||||
cancel: Peruuta
|
||||
enterUsername: Anna käyttäjänimi
|
||||
renotedBy: Buustannut {user}
|
||||
noNotes: Ei lähetyksiä
|
||||
noNotifications: Ei ilmoituksia
|
||||
instance: Instanssi
|
||||
settings: Asetukset
|
||||
basicSettings: Perusasetukset
|
||||
otherSettings: Muut asetukset
|
||||
openInWindow: Avaa ikkunaan
|
||||
profile: Profiili
|
||||
timeline: Aikajana
|
||||
noAccountDescription: Käyttäjä ei ole vielä kirjoittanut kuvaustaan vielä.
|
||||
login: Kirjaudu sisään
|
||||
loggingIn: Kirjautuu sisään
|
||||
logout: Kirjaudu ulos
|
||||
uploading: Tallentaa ylös...
|
||||
save: Tallenna
|
||||
favorites: Kirjanmerkit
|
||||
unfavorite: Poista kirjanmerkeistä
|
||||
favorited: Lisätty kirjanmerkkeihin.
|
||||
alreadyFavorited: Lisätty jo kirjanmerkkeihin.
|
||||
cantFavorite: Ei voitu lisätä kirjanmerkkeihin.
|
||||
pin: Kiinnitä profiiliin
|
||||
unpin: Irroita profiilista
|
||||
delete: Poista
|
||||
forgotPassword: Unohtunut salasana
|
||||
search: Etsi
|
||||
notifications: Ilmoitukset
|
||||
password: Salasana
|
||||
ok: OK
|
||||
noThankYou: Ei kiitos
|
||||
signup: Rekisteröidy
|
||||
users: Käyttäjät
|
||||
addUser: Lisää käyttäjä
|
||||
addInstance: Lisää instanssi
|
||||
favorite: Lisää kirjanmerkkeihin
|
||||
copyContent: Kopioi sisältö
|
||||
deleteAndEdit: Poista ja muokkaa
|
||||
copyLink: Kopioi linkki
|
||||
makeFollowManuallyApprove: Seuraajapyyntö vaatii hyväksymistä
|
||||
follow: Seuraa
|
||||
pinned: Kiinnitä profiiliin
|
||||
followRequestPending: Seuraajapyyntö odottaa
|
||||
you: Sinä
|
||||
unrenote: Peruuta buustaus
|
||||
reaction: Reaktiot
|
||||
reactionSettingDescription2: Vedä uudelleenjärjestelläksesi, napsauta poistaaksesi,
|
||||
paina "+" lisätäksesi.
|
||||
attachCancel: Poista liite
|
||||
enterFileName: Anna tiedostonimi
|
||||
mute: Hiljennä
|
||||
unmute: Poista hiljennys
|
||||
headlineMisskey: Avoimen lähdekoodin, hajautettu sosiaalisen median alusta, joka on
|
||||
ikuisesti ilmainen! 🚀
|
||||
monthAndDay: '{day}/{month}'
|
||||
deleteAndEditConfirm: Oletko varma, että haluat poistaa tämän lähetyksen ja muokata
|
||||
sitä? Menetät kaikki reaktiot, buustaukset ja vastaukset lähetyksestäsi.
|
||||
addToList: Lisää listaan
|
||||
sendMessage: Lähetä viesti
|
||||
reply: Vastaa
|
||||
loadMore: Lataa enemmän
|
||||
showMore: Näytä enemmän
|
||||
receiveFollowRequest: Seuraajapyyntö vastaanotettu
|
||||
followRequestAccepted: Seuraajapyyntö hyväksytty
|
||||
mentions: Maininnat
|
||||
importAndExport: Tuo/Vie Tietosisältö
|
||||
import: Tuo
|
||||
export: Vie
|
||||
files: Tiedostot
|
||||
download: Lataa
|
||||
unfollowConfirm: Oletko varma, ettet halua seurata enää käyttäjää {name}?
|
||||
noLists: Sinulla ei ole listoja
|
||||
note: Viesti
|
||||
notes: Viestit
|
||||
following: Seuraa
|
||||
createList: Luo lista
|
||||
manageLists: Hallitse listoja
|
||||
error: Virhe
|
||||
somethingHappened: On tapahtunut virhe
|
||||
retry: Yritä uudelleen
|
||||
pageLoadError: Virhe ladattaessa sivua.
|
||||
serverIsDead: Tämä palvelin ei vastaa. Yritä hetken kuluttua uudelleen.
|
||||
youShouldUpgradeClient: Nähdäksesi tämän sivun, virkistä päivittääksesi asiakasohjelmasi.
|
||||
privacy: Tietosuoja
|
||||
defaultNoteVisibility: Oletusnäkyvyys
|
||||
followRequest: Seuraajapyyntö
|
||||
followRequests: Seuraajapyynnöt
|
||||
unfollow: Poista seuraaminen
|
||||
enterEmoji: Syötä emoji
|
||||
renote: Buustaa
|
||||
renoted: Buustattu.
|
||||
cantRenote: Tätä lähetystä ei voi buustata.
|
||||
cantReRenote: Buustausta ei voi buustata.
|
||||
quote: Lainaus
|
||||
pinnedNote: Lukittu lähetys
|
||||
clickToShow: Napsauta nähdäksesi
|
||||
sensitive: Herkkää sisältöä (NSFW)
|
||||
add: Lisää
|
||||
enableEmojiReactions: Ota käyttöön emoji-reaktiot
|
||||
showEmojisInReactionNotifications: Näytä emojit reaktioilmoituksissa
|
||||
reactionSetting: Reaktiot näytettäväksi reaktiovalitsimessa
|
||||
rememberNoteVisibility: Muista lähetyksen näkyvyysasetukset
|
||||
markAsSensitive: Merkitse herkäksi sisällöksi (NSFW)
|
||||
unmarkAsSensitive: Poista merkintä herkkää sisältöä (NSFW)
|
||||
renoteMute: Hiljennä buustit
|
||||
renoteUnmute: Poista buustien hiljennys
|
||||
block: Estä
|
||||
unblock: Poista esto
|
||||
unsuspend: Poista keskeytys
|
||||
suspend: Keskeytys
|
||||
blockConfirm: Oletko varma, että haluat estää tämän tilin?
|
||||
unblockConfirm: Oletko varma, että haluat poistaa tämän tilin eston?
|
||||
selectAntenna: Valitse antenni
|
||||
selectWidget: Valitse vimpain
|
||||
editWidgets: Muokkaa vimpaimia
|
||||
editWidgetsExit: Valmis
|
||||
emoji: Emoji
|
||||
emojis: Emojit
|
||||
emojiName: Emojin nimi
|
||||
emojiUrl: Emojin URL-linkki
|
||||
cacheRemoteFiles: Taltioi etätiedostot välimuistiin
|
||||
flagAsBot: Merkitse tili botiksi
|
||||
flagAsBotDescription: Ota tämä vaihtoehto käyttöön, jos tätä tiliä ohjaa ohjelma.
|
||||
Jos se on käytössä, se toimii lippuna muille kehittäjille, jotta estetään loputtomat
|
||||
vuorovaikutusketjut muiden bottien kanssa ja säädetään Firefishn sisäiset järjestelmät
|
||||
käsittelemään tätä tiliä botina.
|
||||
flagAsCat: Oletko kissa? 🐱
|
||||
flagAsCatDescription: Saat kissan korvat ja puhut kuin kissa!
|
||||
flagSpeakAsCat: Puhu kuin kissa
|
||||
flagShowTimelineReplies: Näytä vastaukset aikajanalla
|
||||
addAccount: Lisää tili
|
||||
loginFailed: Kirjautuminen epäonnistui
|
||||
showOnRemote: Katsele etäinstanssilla
|
||||
general: Yleistä
|
||||
accountMoved: 'Käyttäjä on muuttanut uuteen tiliin:'
|
||||
wallpaper: Taustakuva
|
||||
setWallpaper: Aseta taustakuva
|
||||
searchWith: 'Etsi: {q}'
|
||||
youHaveNoLists: Sinulla ei ole listoja
|
||||
followConfirm: Oletko varma, että haluat seurata käyttäjää {name}?
|
||||
host: Isäntä
|
||||
selectUser: Valitse käyttäjä
|
||||
annotation: Kommentit
|
||||
registeredAt: Rekisteröity
|
||||
latestRequestReceivedAt: Viimeisin pyyntö vastaanotettu
|
||||
latestRequestSentAt: Viimeisin pyyntö lähetetty
|
||||
storageUsage: Tallennustilan käyttö
|
||||
charts: Kaaviot
|
||||
stopActivityDelivery: Lopeta toimintojen lähettäminen
|
||||
blockThisInstance: Estä tämä instanssi
|
||||
operations: Toiminnot
|
||||
metadata: Metatieto
|
||||
monitor: Seuranta
|
||||
jobQueue: Työjono
|
||||
cpuAndMemory: Prosessori ja muisti
|
||||
network: Verkko
|
||||
disk: Levy
|
||||
clearCachedFiles: Tyhjennä välimuisti
|
||||
clearCachedFilesConfirm: Oletko varma, että haluat tyhjentää kaikki välimuistiin tallennetut
|
||||
etätiedostot?
|
||||
blockedInstances: Estetyt instanssit
|
||||
hiddenTags: Piilotetut asiatunnisteet
|
||||
mention: Maininta
|
||||
copyUsername: Kopioi käyttäjänimi
|
||||
searchUser: Etsi käyttäjää
|
||||
showLess: Sulje
|
||||
youGotNewFollower: seurasi sinua
|
||||
directNotes: Yksityisviestit
|
||||
driveFileDeleteConfirm: Oletko varma, että haluat poistaa tiedoston " {name}"? Se
|
||||
poistetaan kaikista viesteistä, jotka sisältävät sen liitetiedostona.
|
||||
importRequested: Olet pyytänyt viemistä. Tämä voi viedä hetken.
|
||||
exportRequested: Olet pyytänyt tuomista. Tämä voi viedä hetken. Se lisätään asemaan
|
||||
kun tuonti valmistuu.
|
||||
lists: Listat
|
||||
followers: Seuraajat
|
||||
followsYou: Seuraa sinua
|
||||
pageLoadErrorDescription: Tämä yleensä johtuu verkkovirheistä tai selaimen välimuistista.
|
||||
Kokeile tyhjentämällä välimuisti ja yritä sitten hetken kuluttua uudelleen.
|
||||
enterListName: Anna listalle nimi
|
||||
instanceInfo: Instanssin tiedot
|
||||
clearQueue: Tyhjennä jono
|
||||
suspendConfirm: Oletko varma, että haluat keskeyttää tämän tilin?
|
||||
unsuspendConfirm: Oletko varma, että haluat poistaa tämän tilin keskeytyksen?
|
||||
selectList: Valitse lista
|
||||
customEmojis: Kustomoitu Emoji
|
||||
addEmoji: Lisää
|
||||
settingGuide: Suositellut asetukset
|
||||
cacheRemoteFilesDescription: Kun tämä asetus ei ole käytössä, etätiedostot on ladattu
|
||||
suoraan etäinstanssilta. Asetuksen poistaminen käytöstä vähentää tallennustilan
|
||||
käyttöä, mutta lisää verkkoliikennettä kun pienoiskuvat eivät muodostu.
|
||||
flagSpeakAsCatDescription: Lähetyksesi nyanifioidaan, kun olet kissatilassa
|
||||
flagShowTimelineRepliesDescription: Näyttää käyttäjien vastaukset muiden käyttäjien
|
||||
lähetyksiin aikajanalla, jos se on päällä.
|
||||
autoAcceptFollowed: Automaattisesti hyväksy seuraamispyynnöt käyttäjiltä, joita seuraat
|
||||
perHour: Tunnissa
|
||||
removeWallpaper: Poista taustakuva
|
||||
recipient: Vastaanottaja(t)
|
||||
federation: Federaatio
|
||||
software: Ohjelmisto
|
||||
proxyAccount: Proxy-tili
|
||||
proxyAccountDescription: Välitystili (Proxy-tili) on tili, joka toimii käyttäjien
|
||||
etäseuraajana tietyin edellytyksin. Kun käyttäjä esimerkiksi lisää etäkäyttäjän
|
||||
luetteloon, etäkäyttäjän toimintaa ei toimiteta instanssiin, jos yksikään paikallinen
|
||||
käyttäjä ei seuraa kyseistä käyttäjää, joten välitystili seuraa sen sijaan.
|
||||
latestStatus: Viimeisin tila
|
||||
selectInstance: Valitse instanssi
|
||||
instances: Instanssit
|
||||
perDay: Päivässä
|
||||
version: Versio
|
||||
statistics: Tilastot
|
||||
clearQueueConfirmTitle: Oletko varma, että haluat tyhjentää jonon?
|
||||
introMisskey: Tervetuloa! Firefish on avoimen lähdekoodin, hajautettu sosiaalisen median
|
||||
alusta, joka on ikuisesti ilmainen! 🚀
|
||||
clearQueueConfirmText: Mitkään välittämättömät lähetykset, jotka ovat jonossa, eivät
|
||||
federoidu. Yleensä tätä toimintoa ei tarvita.
|
||||
blockedInstancesDescription: Lista instanssien isäntänimistä, jotka haluat estää.
|
||||
Listatut instanssit eivät kykene kommunikoimaan enää tämän instanssin kanssa.
|
||||
security: Turvallisuus
|
||||
retypedNotMatch: Syöte ei kelpaa.
|
||||
fromDrive: Asemasta
|
||||
keepOriginalUploading: Säilytä alkuperäinen kuva
|
||||
uploadFromUrlDescription: Tiedoston URL, jonka haluat ylösladata
|
||||
themeForLightMode: Teema vaaleassa tilassa
|
||||
theme: Teemat
|
||||
themeForDarkMode: Teema tummassa tilassa
|
||||
drive: Asema
|
||||
darkThemes: Tummat teemat
|
||||
copyUrl: Kopioi URL-linkki
|
||||
rename: Uudelleennimeä
|
||||
maintainerName: Ylläpitäjä
|
||||
maintainerEmail: Ylläpitäjän sähköposti
|
||||
tosUrl: Palvelun ehdot URL-linkki
|
||||
thisYear: Vuosi
|
||||
backgroundImageUrl: Taustakuvan URL-linkki
|
||||
basicInfo: Perustiedot
|
||||
pinnedPagesDescription: Kirjoita niiden sivujen polut, jotka haluat liittää tämän
|
||||
instanssin yläsivulle rivinvaihdoin erotettuna.
|
||||
hcaptchaSiteKey: Sivuston avain
|
||||
hcaptchaSecretKey: Salausavain
|
||||
silencedInstances: Hiljennetyt instanssit
|
||||
muteAndBlock: Hiljennykset ja estetyt
|
||||
mutedUsers: Hiljennetyt käyttäjät
|
||||
blockedUsers: Estetyt käyttäjät
|
||||
noUsers: Ei yhtään käyttäjää
|
||||
noInstances: Ei yhtään instanssia
|
||||
editProfile: Muokkaa profiilia
|
||||
noteDeleteConfirm: Oletko varma, että haluat poistaa tämän viestin?
|
||||
pinLimitExceeded: Et voi kiinnittää enempää viestejä
|
||||
intro: Firefish -asennus valmis! Ole hyvä ja luo admin-käyttäjä.
|
||||
done: Valmis
|
||||
processing: Suorittaa
|
||||
preview: Esikatselu
|
||||
default: Oletus
|
||||
defaultValueIs: 'Oletus: {value}'
|
||||
noCustomEmojis: Ei emojia
|
||||
noJobs: Ei töitä
|
||||
federating: Federoi
|
||||
blocked: Estetty
|
||||
silenced: Hiljennetty
|
||||
suspended: Keskeytetty
|
||||
all: Kaikki
|
||||
publishing: Julkaisee
|
||||
subscribing: Tilaa
|
||||
notResponding: Ei vastaa
|
||||
instanceFollowing: Seuraa instanssia
|
||||
instanceFollowers: Instanssin seuraajat
|
||||
instanceUsers: Instanssin käyttäjät
|
||||
changePassword: Muuta salasana
|
||||
newPasswordRetype: Uudelleensyötä uusi salasana
|
||||
more: Lisää!
|
||||
featured: Esillä
|
||||
usernameOrUserId: Käyttäjänimi tai käyttäjä id
|
||||
noSuchUser: Käyttäjää ei löydy
|
||||
lookup: Hae
|
||||
announcements: Tiedoitteet
|
||||
imageUrl: Kuva URL-linkki
|
||||
removed: Onnistuneesti poistettu
|
||||
removeAreYouSure: Oletko varma, että haluat poistaa " {x}"?
|
||||
resetAreYouSure: Haluatko nollata?
|
||||
saved: Tallennettu
|
||||
messaging: Juttele
|
||||
upload: Lataa ylös
|
||||
fromUrl: URL:stä
|
||||
uploadFromUrl: Ylöslataa URL:stä
|
||||
uploadFromUrlRequested: Ylöslataus pyydetty
|
||||
uploadFromUrlMayTakeTime: Voi viedä hetki, kun ylöslataus on valmis.
|
||||
explore: Tutustu
|
||||
messageRead: Lue
|
||||
noMoreHistory: Ei lisää historiaa
|
||||
startMessaging: Aloita uusi juttelu
|
||||
manageGroups: Hallitse ryhmiä
|
||||
nUsersRead: lukenut {n}
|
||||
agreeTo: Hyväksyn {0}
|
||||
tos: Palvelun ehdot
|
||||
start: Aloita
|
||||
home: Koti
|
||||
remoteUserCaution: Etäkäyttäjän tiedot saattavat olla puutteellisia.
|
||||
light: Vaalea
|
||||
dark: Tumma
|
||||
lightThemes: Vaaleat teemat
|
||||
syncDeviceDarkMode: Synkronoi tumma tila laitteen asetuksen mukaan
|
||||
fileName: Tiedostonimi
|
||||
selectFile: Valitse tiedosto
|
||||
selectFiles: Valitse tiedostot
|
||||
selectFolder: Valitse kansio
|
||||
selectFolders: Valitse kansiot
|
||||
renameFile: Uudelleennimeä tiedosto
|
||||
folderName: Kansionimi
|
||||
createFolder: Luo kansio
|
||||
renameFolder: Uudelleennimeä kansio
|
||||
deleteFolder: Poista kansio
|
||||
addFile: Lisää tiedosto
|
||||
emptyDrive: Asemasi on tyhjä
|
||||
emptyFolder: Tämä kansio on tyhjä
|
||||
unableToDelete: Ei voitu poistaa
|
||||
inputNewFileName: Syötä uusi tiedostonimi
|
||||
inputNewDescription: Syötä uusi kuvateksti
|
||||
inputNewFolderName: Syötä uusi kansionimi
|
||||
hasChildFilesOrFolders: Koska kansio ei ole tyhjä, sitä ei voi poistaa.
|
||||
avatar: Kuvake
|
||||
banner: Banneri
|
||||
nsfw: Herkkää sisältöä (NSFW)
|
||||
whenServerDisconnected: Kun yhteys palvelimeen menetetään
|
||||
disconnectedFromServer: Yhteys palvelimeen katkennut
|
||||
reload: Päivitä
|
||||
doNothing: Hylkää
|
||||
reloadConfirm: Haluaisitko päivittää aikajanan?
|
||||
unwatch: Lopeta katselu
|
||||
watch: Katsele
|
||||
accept: Hyväksy
|
||||
reject: Hylkää
|
||||
normal: Normaali
|
||||
instanceName: Instanssin nimi
|
||||
thisMonth: Kuukausi
|
||||
today: Tänään
|
||||
monthX: '{month}'
|
||||
connectService: Yhdistä
|
||||
disconnectService: Katkaise yhteys
|
||||
enableLocalTimeline: Ota käyttöön paikallinen aikajana
|
||||
enableGlobalTimeline: Ota käyttöön globaali aikajana
|
||||
enableRecommendedTimeline: Ota käyttöön suositellut -aikajana
|
||||
registration: Rekisteröinti
|
||||
enableRegistration: Ota käyttöön uuden käyttäjän rekisteröinti
|
||||
driveCapacityPerLocalAccount: Aseman kapasiteetti paikallista käyttäjää kohti
|
||||
driveCapacityPerRemoteAccount: Aseman kapasiteetti etäkäyttäjää kohti
|
||||
inMb: megatavuissa
|
||||
bannerUrl: Bannerikuvan URL-linkki
|
||||
pinnedUsers: Kiinnitetyt käyttäjät
|
||||
pinnedPages: Kiinnitetyt sivut
|
||||
pinnedClipId: Kiinnitettävän leikkeen ID
|
||||
enableHcaptcha: Ota käyttöön hCaptcha-tunnistus
|
||||
recaptcha: CAPTCHA uudelleen
|
||||
enableRecaptcha: Ota käyttöön CAPTCHA uudelleen
|
||||
recaptchaSiteKey: Sivuston avain
|
||||
recaptchaSecretKey: Salausavain
|
||||
silenceThisInstance: Hiljennä tämä instanssi
|
||||
silencedInstancesDescription: Lista isäntänimistä, joka haluat hiljentää. Tilejä listassa
|
||||
kohdellaan "hiljennettynä", ne voivat tehdä seuraajapyyntöjä ja eivät voi tehdä
|
||||
mainintoja paikallistileistä jossei seurattu. Tämä ei vaikuta estettyihin instansseihin.
|
||||
hiddenTagsDescription: 'Listaa aihetunnisteet (ilman #-merkkiä) aihetunnisteet, jotka
|
||||
haluat piilottaa trendaavista ja Tutustu-osiosta. Piilotetut aihetunnisteet ovat
|
||||
kuitenkin löydettävissä muilla keinoilla. Estetyt instanssit eivät vaikuta, vaikka
|
||||
listattu tähän.'
|
||||
currentPassword: Nykyinen salasana
|
||||
newPassword: Uusi salasana
|
||||
attachFile: Liitetyt tiedostot
|
||||
keepOriginalUploadingDescription: Tallentaa alkuperäisen kuvan sellaisenaan. Jos kytketty
|
||||
päältä, webissä näytettävä versio luodaan ylöslatauksen yhteydessä.
|
||||
remove: Poista
|
||||
circularReferenceFolder: Kohdekansio on kansion alikansio, jonka haluat siirtää.
|
||||
deleteAreYouSure: Oletko varma, että haluat poistaa kokonaan" {x}"?
|
||||
yearsOld: '{age} vuotias'
|
||||
activity: Aktiivisuus
|
||||
images: Kuvat
|
||||
birthday: Syntymäpäivä
|
||||
registeredDate: Liittynyt
|
||||
location: Sijainti
|
||||
disablingTimelinesInfo: Järjestelmänvalvojilla ja moderaattoreilla on aina pääsy kaikille
|
||||
aikajanoille, vaikka olisikin poistettu käytöstä.
|
||||
dayX: '{day}'
|
||||
yearX: '{year}'
|
||||
pages: Sivut
|
||||
integration: Integraatiot
|
||||
instanceDescription: Instanssin kuvaus
|
||||
invite: Kutsu
|
||||
iconUrl: Ikoni URL-linkki
|
||||
pinnedUsersDescription: Listaa käyttäjänimet eroteltuna rivivaihdoin kiinnittääksesi
|
||||
ne "Tutustu" välilehteen.
|
||||
pinnedNotes: Kiinnitetyt viestit
|
||||
hcaptcha: hCaptcha-tunnistus
|
||||
antennaSource: Antennin lähde
|
||||
invitationCode: Kutsukoodi
|
||||
checking: Tarkistetaan...
|
||||
passwordNotMatched: Ei vastaa
|
||||
doing: Käsittelee...
|
||||
category: Kategoria
|
||||
tags: Tagit
|
||||
disableAnimatedMfm: Poista MFM -animaatiot käytöstä
|
||||
openImageInNewTab: Avaa kuvat uuteen välilehteen
|
||||
dashboard: Kojelauta
|
||||
local: Paikallinen
|
||||
remote: Etä
|
||||
total: Yhteensä
|
||||
weekOverWeekChanges: Muutokset viime viikkoon
|
||||
objectStorageRegion: Alue
|
||||
popout: Ulosvedettävä
|
||||
volume: Äänenvoimakkuus
|
||||
masterVolume: Master äänenvoimakkuus
|
||||
details: Yksityiskohdat
|
||||
chooseEmoji: Valitse emoji
|
||||
descendingOrder: Laskevasti
|
||||
scratchpad: Raaputusalusta
|
||||
output: Ulostulo
|
||||
invisibleNote: Näkymätön viesti
|
||||
enableInfiniteScroll: Lataa enemmän automaattisesti
|
||||
visibility: Näkyvyys
|
||||
useCw: Piilota sisältö
|
||||
poll: Kysely
|
||||
enablePlayer: Avaa videotoistimeen
|
||||
enterFileDescription: Syötä tiedostokuvaus
|
||||
author: Kirjoittaja
|
||||
manage: Hallinta
|
||||
description: Kuvaus
|
||||
describeFile: Lisää tiedostokuvaus
|
||||
height: Korkeus
|
||||
large: Suuri
|
||||
medium: Keskikokoinen
|
||||
small: Pieni
|
||||
other: Muu
|
||||
create: Luo
|
||||
regenerateLoginTokenDescription: Luo uudelleen kirjautumisen aikana sisäisesti käytettävän
|
||||
tunnuksen. Normaalisti tämä toiminto ei ole tarpeen. Jos tunniste luodaan uudelleen,
|
||||
kaikki laitteet kirjautuvat ulos.
|
||||
setMultipleBySeparatingWithSpace: Erottele useat merkinnät välilyönneillä.
|
||||
fileIdOrUrl: Tiedosto ID tai URL-linkki
|
||||
behavior: Käytös
|
||||
instanceTicker: Viestejä koskevat instanssitiedot
|
||||
waitingFor: Odottaa {x}
|
||||
random: Satunnainen
|
||||
system: Järjestelmä
|
||||
switchUi: Ulkoasu
|
||||
createNew: Luo uusi
|
||||
followersCount: Seuraajien määrä
|
||||
renotedCount: Saatujen buustausten määrä
|
||||
followingCount: Seurattujen tilien määrä
|
||||
notSet: Ei asetettu
|
||||
nUsers: '{n} Käyttäjää'
|
||||
nNotes: '{n} Viestiä'
|
||||
sendErrorReports: Lähetä virheraportteja
|
||||
backgroundColor: Taustaväri
|
||||
accentColor: Korostusväri
|
||||
textColor: Tekstin väri
|
||||
advanced: Edistynyt
|
||||
saveAs: Tallenna nimellä...
|
||||
invalidValue: Epäkelpo arvo.
|
||||
registry: Rekisteri
|
||||
closeAccount: Sulje tili
|
||||
currentVersion: Nykyinen versio
|
||||
capacity: Kapasiteetti
|
||||
clear: Palaa
|
||||
_theme:
|
||||
explore: Tutustu teemoihin
|
||||
silenceConfirm: Oletko varma, että haluat hiljentää tämän käyttäjän?
|
||||
notesAndReplies: Viestit ja vastaukset
|
||||
withFiles: Tiedostot sisältyvät
|
||||
silence: Hiljennä
|
||||
popularTags: Suositut tagit
|
||||
userList: Listat
|
||||
about: Tietoja
|
||||
aboutFirefish: Tietoja Firefishstä
|
||||
exploreFediverse: Tutustu fediverseen
|
||||
recentlyUpdatedUsers: Vastikään lisätyt käyttäjät
|
||||
recentlyRegisteredUsers: Uudet liittyneet jäyttäjät
|
||||
recentlyDiscoveredUsers: Vastikään löydetyt käyttäjät
|
||||
exploreUsersCount: Täällä on {count} käyttäjää
|
||||
share: Jaa
|
||||
moderation: Sisällön valvonta
|
||||
nUsersMentioned: Mainittu {n} käyttäjältä
|
||||
securityKey: Turva-avain
|
||||
securityKeyName: Avainnimi
|
||||
registerSecurityKey: Rekisteröi turva-avain
|
||||
lastUsed: Viimeksi käytetty
|
||||
unregister: Poista rekisteröinti
|
||||
passwordLessLogin: Salasanaton sisäänkirjautuminen
|
||||
cacheClear: Tyhjennä välimuisti
|
||||
markAsReadAllNotifications: Merkitse kaikki ilmoitukset luetuksi
|
||||
markAsReadAllUnreadNotes: Merkitse kaikki viestit luetuiksi
|
||||
uploadFolder: Oletuskansio ylöslatauksille
|
||||
createGroup: Luo ryhmä
|
||||
group: Ryhmä
|
||||
groups: Ryhmät
|
||||
ownedGroups: Omistetut ryhmät
|
||||
help: Apua
|
||||
inputMessageHere: Syötä viesti tähän
|
||||
close: Sulje
|
||||
joinedGroups: Liittyneet ryhmät
|
||||
invites: Kutsut
|
||||
groupName: Ryhmänimi
|
||||
members: Jäsenet
|
||||
language: Kieli
|
||||
signinHistory: Kirjautumishistoria
|
||||
docSource: Tämän dokumentin lähde
|
||||
createAccount: Luo tili
|
||||
existingAccount: Olemassa oleva tili
|
||||
promotion: Edistetty
|
||||
promote: Edistää
|
||||
numberOfDays: Päivien määrä
|
||||
accountSettings: Tilin asetukset
|
||||
objectStorage: Objektitallennus
|
||||
useObjectStorage: Käytä objektitallennusta
|
||||
objectStorageBaseUrl: Perus URL-linkki
|
||||
objectStorageBaseUrlDesc: "Viitteenä käytetty URL-linkki. Määritä CDN:n tai välityspalvelimen\
|
||||
\ URL-linkki, jos käytät kumpaakin.\nKäytä S3:lle 'https://<bucket>.s3.amazonaws.com'\
|
||||
\ ja GCS:lle tai vastaaville palveluille 'https://storage.googleapis.com/<bucket>'\
|
||||
\ jne."
|
||||
objectStorageBucket: Kauha
|
||||
newNoteRecived: Uusia viestejä
|
||||
smtpPort: Portti
|
||||
instanceMute: Instanssin mykistys
|
||||
repliesCount: Lähetettyjen vastausten määrä
|
||||
updatedAt: Päivitetty
|
||||
notFound: Ei löydy
|
||||
useOsNativeEmojis: Käytä käyttöjärjestelmän natiivi-Emojia
|
||||
joinOrCreateGroup: Tule kutsutuksi ryhmään tai luo oma ryhmä.
|
||||
text: Teksti
|
||||
usernameInvalidFormat: Käytä isoja ja pieniä kirjaimia, numeroita ja erikoismerkkejä.
|
||||
unsilenceConfirm: Oletko varma, että haluat poistaa käyttäjän hiljennyksen?
|
||||
popularUsers: Suositut käyttäjät
|
||||
moderator: Moderaattori
|
||||
twoStepAuthentication: Kaksivaiheinen tunnistus
|
||||
notFoundDescription: URL-linkkiin liittyvää sivua ei löytynyt.
|
||||
antennaKeywords: Kuunneltavat avainsanat
|
||||
antennaExcludeKeywords: Poislasketut avainsanat
|
||||
antennaKeywordsDescription: Erottele välilyönneillä AND-ehtoa varten tai rivinvaihdolla
|
||||
OR-ehtoa varten.
|
||||
notifyAntenna: Ilmoita uusista viesteistä
|
||||
withFileAntenna: Vain viestit tiedoston kanssa
|
||||
enableServiceworker: Ota käyttöön Push-notifikaatiot selaimessasi
|
||||
antennaUsersDescription: Luettele yksi käyttäjänimi rivi kohti
|
||||
antennaInstancesDescription: Luettele yksi instanssi riviä kohti
|
||||
caseSensitive: Isot ja pienet kirjaimet
|
||||
withReplies: Sisällytä vastaukset
|
||||
connectedTo: Seuraavat tili(t) on yhdistetty
|
||||
unsilence: Poista hiljennys
|
||||
administrator: Järjestelmänvalvoja
|
||||
token: Merkki
|
||||
resetPassword: Resetoi salasana
|
||||
reduceUiAnimation: Vähennä käyttöliittymän animaatioita
|
||||
transfer: Siirrä
|
||||
messagingWithUser: Yksityisjuttelu
|
||||
title: Otsikko
|
||||
enable: Ota käyttöön
|
||||
next: Seuraava
|
||||
retype: Syötä uudelleen
|
||||
noteOf: Lähettänyt {user}
|
||||
inviteToGroup: Kutsu ryhmään
|
||||
quoteAttached: Lainaus
|
||||
quoteQuestion: Liitä lainauksena?
|
||||
noMessagesYet: Ei vielä viestejä
|
||||
newMessageExists: Uusia viestejä
|
||||
onlyOneFileCanBeAttached: Voit liittää vain yhden tiedoston viestiin
|
||||
signinRequired: Ole hyvä ja rekisteröidy tai kirjaudu sisään jatkaaksesi
|
||||
invitations: Kutsut
|
||||
available: Saatavilla
|
||||
unavailable: Ei saatavissa
|
||||
tooShort: Liian lyhyt
|
||||
tooLong: Liian pitkä
|
||||
weakPassword: Heikko salasana
|
||||
normalPassword: Kohtalainen salasana
|
||||
strongPassword: Vahva salasana
|
||||
passwordMatched: Vastaa
|
||||
signinWith: Kirjaudu sisään {x}
|
||||
signinFailed: Ei voitu kirjautua sisään. Annettu käyttäjänimi tai salasana virheellinen.
|
||||
tapSecurityKey: Napsauta turva-avaintasi
|
||||
or: Tai
|
||||
uiLanguage: Anna käyttöliittymän kieli
|
||||
groupInvited: Sinut on kutsuttu ryhmään
|
||||
aboutX: Tietoja {x}
|
||||
disableDrawer: Älä käytä laatikkotyyppisiä valikoita
|
||||
youHaveNoGroups: Sinulla ei ole ryhmiä
|
||||
noHistory: Ei historiaa saatavilla
|
||||
regenerate: Uudelleenluo
|
||||
fontSize: Kirjasinkoko
|
||||
dayOverDayChanges: Muutokset eiliseen
|
||||
clientSettings: Asiakkaan asetukset
|
||||
hideThisNote: Piilota tämä viesti
|
||||
showFeaturedNotesInTimeline: Näytä esillä olevat viestit aikajanalla
|
||||
objectStorageBucketDesc: Määritä palveluntarjoajasi käyttämä kauhan nimi.
|
||||
objectStoragePrefix: Etuliite
|
||||
objectStorageEndpoint: Päätepiste
|
||||
objectStorageRegionDesc: Määritä alue, kuten "xx-east-1". Jos palvelusi ei tee eroa
|
||||
alueiden välillä, jätä tämä kohta tyhjäksi tai kirjoita "us-east-1".
|
||||
objectStorageUseSSL: Käytä SSL-salausta
|
||||
objectStorageUseSSLDesc: Poista tämä käytöstä, jos et aio käyttää HTTPS:ää API-yhteyksissä
|
||||
objectStorageUseProxy: Yhdistä välityspalvelimen kautta
|
||||
objectStorageUseProxyDesc: Poista tämä käytöstä, jos et aio käyttää välityspalvelinta
|
||||
API-yhteyksiä varten
|
||||
objectStorageSetPublicRead: Aseta "public-read" ylöslataukseen
|
||||
serverLogs: Palvelimen lokit
|
||||
deleteAll: Poista kaikki
|
||||
showFixedPostForm: Näytä viesti-ikkuna aikajanan yläpuolella
|
||||
sounds: Äänet
|
||||
listen: Kuuntele
|
||||
none: Ei mitään
|
||||
showInPage: Näytä sivulla
|
||||
recentUsed: Vastikään käytetty
|
||||
install: Asenna
|
||||
uninstall: Poista asennus
|
||||
installedApps: Hyväksytyt sovellukset
|
||||
nothing: Ei nähtävää täällä
|
||||
state: Tila
|
||||
sort: Järjestä
|
||||
ascendingOrder: Nousevasti
|
||||
scratchpadDescription: Raaputusalusta tarjoaa ympäristön AiScript-kokeiluja varten.
|
||||
Voit kirjoittaa, suorittaa ja tarkistaa sen tulokset vuorovaikutuksessa siinä olevan
|
||||
Firefishn kanssa.
|
||||
script: Skripti
|
||||
disablePagesScript: Poista AiScript käytöstä sivuilla
|
||||
updateRemoteUser: Päivitä etäkäyttäjän tiedot
|
||||
deleteAllFiles: Poista kaikki tiedostot
|
||||
deleteAllFilesConfirm: Oletko varma, että haluat poistaa kaikki tiedostot?
|
||||
removeAllFollowing: Poista seuraaminen kaikista seuratuista käyttäjistä
|
||||
removeAllFollowingDescription: Tämän suorittaminen poistaa kaikki {host}:n tilit.
|
||||
Suorita tämä, jos instanssia ei esimerkiksi enää ole olemassa.
|
||||
userSuspended: Tämä käyttäjä on hyllytetty.
|
||||
userSilenced: Tämä käyttäjä on hiljennetty.
|
||||
yourAccountSuspendedTitle: Tämä tili on hyllytetty
|
||||
yourAccountSuspendedDescription: Tämä tili on hyllytetty palvelimen palveluehtojen
|
||||
tai vastaavien rikkomisen vuoksi. Ota yhteyttä ylläpitäjään, jos haluat tietää tarkemman
|
||||
syyn. Älä luo uutta tiliä.
|
||||
menu: Valikko
|
||||
divider: Jakaja
|
||||
addItem: Lisää kohde
|
||||
relays: Releet
|
||||
addRelay: Lisää rele
|
||||
inboxUrl: Saavuneen postin URL
|
||||
addedRelays: Lisätyt releet
|
||||
serviceworkerInfo: Pitää ottaa käyttöön Push-notifikaatioissa.
|
||||
deletedNote: Poistetut viestit
|
||||
disablePlayer: Sulje videotoistin
|
||||
expandTweet: Laajenna twiittiä
|
||||
themeEditor: Teemaeditori
|
||||
leaveConfirm: Tallentamattomia muutoksia olemassa. Hylätäänkö ne?
|
||||
plugins: Liitännäiset
|
||||
preferencesBackups: Asetusten varmuuskopiot
|
||||
deck: Kansi
|
||||
undeck: Jätä kansi
|
||||
useBlurEffectForModal: Käytä blur-efektiä modaaleissa
|
||||
useFullReactionPicker: Käytä täysikokoista reaktiovalitsinta
|
||||
width: Leveys
|
||||
generateAccessToken: Luo käyttöoikeustunniste
|
||||
enableAll: Ota käyttöön kaikki
|
||||
disableAll: Poista käytöstä kaikki
|
||||
tokenRequested: Myönnä oikeus tiliin
|
||||
notificationType: Ilmoituksen tyyppi
|
||||
edit: Muokkaa
|
||||
emailServer: Sähköpostipalvelin
|
||||
enableEmail: Ota sähköpostin jakelu käyttöön
|
||||
emailConfigInfo: Käytetään vahvistamaan sähköpostiosoitteesi rekisteröitymisen yhteydessä
|
||||
tai jos unohdat salasanasi
|
||||
email: Sähköposti
|
||||
smtpHost: Isäntä
|
||||
smtpUser: Käyttäjänimi
|
||||
smtpPass: Salasana
|
||||
emptyToDisableSmtpAuth: Jätä käyttäjänimi ja salasana tyhjäksi ohittaaksesi SMTP verifioinnin
|
||||
smtpSecureInfo: Kytke tämä päältä kun käytät STARTTLS
|
||||
testEmail: Kokeile email-lähetystä
|
||||
wordMute: Sanan hiljennys
|
||||
regexpError: Säännöllinen lausekevirhe
|
||||
userSaysSomething: '{name} sanoi jotakin'
|
||||
userSaysSomethingReason: '{name} sanoi {reason}'
|
||||
makeActive: Aktivoi
|
||||
display: Näyttö
|
||||
copy: Kopioi
|
||||
metrics: Mittarit
|
||||
overview: Yleiskatsaus
|
||||
logs: Lokit
|
||||
delayed: Viivästynyt
|
||||
database: Tietokanta
|
||||
channel: Kanavat
|
||||
notificationSetting: Ilmoitusasetukset
|
||||
notificationSettingDesc: Valitse näytettävät ilmoitustyypit.
|
||||
useGlobalSetting: Käytä globaaleja asetuksia
|
||||
regenerateLoginToken: Luo kirjautumistunniste uudelleen
|
||||
sample: Näyte
|
||||
abuseReports: Raportit
|
||||
reportAbuse: Raportti
|
||||
reportAbuseOf: Raportti {name}
|
||||
fillAbuseReportDescription: Täytä tätä raporttia koskevat tiedot. Jos se koskee tiettyä
|
||||
viestiä, ilmoita sen URL-linkki.
|
||||
abuseReported: Raporttisi on lähetetty. Kiitoksia paljon.
|
||||
reporter: Raportoija
|
||||
reporteeOrigin: Ilmoittajan alkuperä
|
||||
reporterOrigin: Raportoijan alkuperä
|
||||
forwardReport: Välitä raportti etäinstanssille
|
||||
forwardReportIsAnonymous: Tilisi sijasta anonyymi järjestelmätili näytetään toimittajana
|
||||
etäinstanssissa.
|
||||
send: Lähetä
|
||||
abuseMarkAsResolved: Merkitse raportti ratkaistuksi
|
||||
openInNewTab: Avaa uuteen välilehteen
|
||||
openInSideView: Avaa sivunäkymään
|
||||
defaultNavigationBehaviour: Navigoinnin oletuskäyttäytyminen
|
||||
editTheseSettingsMayBreakAccount: Näiden asetusten muuttaminen voi vahingoittaa tiliäsi.
|
||||
desktop: Työpöytä
|
||||
clip: Leike
|
||||
optional: Vaihtoehtoinen
|
||||
createNewClip: Luo uusi leike
|
||||
unclip: Poista leike
|
||||
confirmToUnclipAlreadyClippedNote: Tämä viesti on jo osa "{name}"-leikettä. Haluatko
|
||||
sen sijaan poistaa sen tästä leikkeestä?
|
||||
manageAccessTokens: Hallitse käyttöoikeuskoodeja
|
||||
accountInfo: Tilin tiedot
|
||||
notesCount: Viestien määrä
|
||||
renotesCount: Lähetettyjen buustausten määrä
|
||||
repliedCount: Saatujen vastausten määrä
|
||||
sentReactionsCount: Lähetettyjen reaktioiden määrä
|
||||
receivedReactionsCount: Saatujen reaktioiden määrä
|
||||
pollVotesCount: Lähetettyjen kyselyäänien määrä
|
||||
pollVotedCount: Saatujen kyselyäänien määrä
|
||||
yes: Kyllä
|
||||
no: Ei
|
||||
driveFilesCount: Tiedostojen määrä asemalla
|
||||
driveUsage: Aseman tilankäyttö
|
||||
noCrawle: Hylkää hakukoneindeksointi
|
||||
noCrawleDescription: Pyydä hakukoneita olemaan indeksoimatta profiilisivuasi, viestejäsi,
|
||||
sivujasi jne.
|
||||
alwaysMarkSensitive: Merkitse oletusarvoisesti herkäksi sisällöksi (NSFW)
|
||||
loadRawImages: Alkuperäisten kuvien lataaminen pikkukuvien näyttämisen sijaan
|
||||
disableShowingAnimatedImages: Älä näytä animoituja kuvia
|
||||
verificationEmailSent: Vahvistussähköposti on lähetetty. Seuraa mukana olevaa linkkiä
|
||||
suorittaaksesi vahvistuksen loppuun.
|
||||
emailVerified: Sähköposti on vahvistettu
|
||||
noteFavoritesCount: Kirjanmerkittyjen viestien määrä
|
||||
pageLikedCount: Saatujen Sivu-tykkäysten määrä
|
||||
pageLikesCount: Sivut-tykkäysten määrä
|
||||
contact: Yhteystieto
|
||||
useSystemFont: Käytä järjestelmän oletuskirjasinta
|
||||
clips: Leikkeet
|
||||
experimentalFeatures: Kokeiluluontoiset ominaisuudet
|
||||
developer: Kehittäjä
|
||||
makeExplorable: Tee tili näkyväksi osiossa "Tutustu"
|
||||
makeExplorableDescription: Jos otat tämän pois käytöstä, tilisi ei näy "Tutustu"-osiossa.
|
||||
showGapBetweenNotesInTimeline: Näytä väli viestien välissä aikajanalla
|
||||
duplicate: Monista
|
||||
left: Vasen
|
||||
center: Keskellä
|
||||
wide: Leveä
|
||||
narrow: Kapea
|
||||
reloadToApplySetting: Asetus otetaan käyttöön vain uudelleenladattaessa. Ladataanko
|
||||
uudelleen nyt?
|
||||
showTitlebar: Näytä otsikkorivi
|
||||
clearCache: Tyhjennä välimuisti
|
||||
onlineUsersCount: '{n} käyttäjää online-tilassa'
|
||||
myTheme: Minun teemani
|
||||
value: Arvo
|
||||
saveConfirm: Tallenna muutokset?
|
||||
deleteConfirm: Poistetaanko tosiaan?
|
||||
latestVersion: Uusin versio
|
||||
newVersionOfClientAvailable: Asiakasohjelmiston uudempi versio saatavilla.
|
||||
usageAmount: Käyttö
|
||||
inUse: Käytetty
|
||||
editCode: Muokkaa koodia
|
||||
apply: Käytä
|
||||
receiveAnnouncementFromInstance: Vastaanota ilmoituksia tästä instanssista
|
||||
emailNotification: Sähköposti-ilmoitukset
|
||||
publish: Julkaise
|
||||
inChannelSearch: Etsi kanavalta
|
||||
useReactionPickerForContextMenu: Avaa reaktiovalitsin napsauttamalla oikeaa
|
||||
typingUsers: '{users} kirjoittaa'
|
||||
jumpToSpecifiedDate: Hyppää tiettyyn päivään
|
||||
markAllAsRead: Merkitse kaikki luetuksi
|
||||
goBack: Takaisin
|
||||
unlikeConfirm: Poistatko todella tykkäyksesi?
|
||||
fullView: Täysi koko
|
||||
quitFullView: Poistu täydestä koosta
|
||||
addDescription: Lisää kuvaus
|
||||
markAsReadAllTalkMessages: Merkitse kaikki yksityisviestit luetuiksi
|
||||
appearance: Ulkonäkö
|
||||
messagingWithGroup: Ryhmäjuttelu
|
||||
newPasswordIs: Uusi salasana on "{password}"
|
||||
noFollowRequests: Sinulla ei ole odottavia seuraajapyyntöjä
|
||||
objectStoragePrefixDesc: Tiedostot tallennetaan hakemistoihin tällä etuliitteellä.
|
||||
objectStorageEndpointDesc: Jätä tämä tyhjäksi, jos käytät AWS S3:a. Muuten määritä
|
||||
päätepisteeksi '<host>' tai '<host>:<port>' käyttämästäsi palvelusta riippuen.
|
||||
unableToProcess: Toimenpidettä ei voida suorittaa loppuun
|
||||
installedDate: Hyväksynyt
|
||||
lastUsedDate: Viimeksi käytetty
|
||||
pluginTokenRequestedDescription: Tämä litännäinen voi käyttää tässä asetettuja käyttöoikeuksia.
|
||||
permission: Oikeudet
|
||||
smtpConfig: Lähtevän sähköpostin palvelimen (SMTP) asetukset
|
||||
regexpErrorDescription: 'Säännöllisessä lausekkeessa tapahtui virhe rivillä {line}
|
||||
sanan {tab} sanan mykistäminen rivillä {line}:'
|
||||
emailAddress: Sähköpostiosoite
|
||||
smtpSecure: Käytä implisiittistä SSL/TLS:ää SMTP-yhteyksissä
|
||||
useGlobalSettingDesc: Jos se on päällä, käytetään tilisi ilmoitusasetuksia. Jos se
|
||||
on pois päältä, voit tehdä yksilöllisiä asetuksia.
|
||||
public: Julkinen
|
||||
i18nInfo: Vapaaehtoiset kääntävät Firefishta eri kielille. Voit auttaa osoitteessa
|
||||
{link}.
|
||||
lockedAccountInfo: Ellet aseta postauksen näkyvyydeksi "Vain seuraajille", postauksesi
|
||||
näkyvät kaikille, vaikka vaatisitkin seuraajilta manuaalista hyväksyntää.
|
||||
sendErrorReportsDescription: "Kun tämä on päällä, yksityiskohtaiset virhetiedot jaetaan\
|
||||
\ Firefishn kanssa ongelman ilmetessä, mikä auttaa parantamaan Firefishn laatua.\n\
|
||||
Näihin tietoihin sisältyy esimerkiksi käyttöjärjestelmäversio, käyttämäsi selain,\
|
||||
\ toimintasi Firefishssä jne."
|
||||
createdAt: Luotu
|
||||
youAreRunningUpToDateClient: Käytössäsi on asiakasohjelman uusin versio.
|
||||
needReloadToApply: Uudelleenlataus vaaditaan, jotta tämä näkyy.
|
||||
showingPastTimeline: Näytetään parhaillaan vanhaa aikajanaa
|
||||
userPagePinTip: Voit näyttää viestit täällä valitsemalla yksittäisten viestien valikosta
|
||||
"Kiinnitä profiiliin".
|
||||
notSpecifiedMentionWarning: Tämä viesti sisältää mainintoja käyttäjistä, joita ei
|
||||
ole mainittu vastaanottajina
|
||||
name: Nimi
|
||||
allowedInstances: Sallitut (whitelisted) instanssit
|
||||
hashtags: Aihetunnisteet
|
||||
troubleshooting: Vianetsintä
|
||||
received: Vastaanotettu
|
||||
searchResult: Hakutulokset
|
||||
filter: Suodatin
|
||||
antennas: Antennit
|
||||
noMaintainerInformationWarning: Ylläpitäjän tietoja ei ole konfiguroitu.
|
||||
controlPanel: Hallintapaneeli
|
||||
manageAccounts: Hallitse tilejä
|
||||
makeReactionsPublic: Aseta reaktiohistoria julkiseksi
|
||||
unread: Lukematon
|
||||
deleted: Poistettu
|
||||
editNote: Muokkaa viestiä
|
||||
edited: 'Muokattu klo {date} {time}'
|
||||
avoidMultiCaptchaConfirm: Useiden Captcha-järjestelmien käyttö voi aiheuttaa häiriöitä
|
||||
niiden välillä. Haluatko poistaa käytöstä muut tällä hetkellä käytössä olevat Captcha-järjestelmät?
|
||||
Jos haluat, että ne pysyvät käytössä, paina peruutusnäppäintä.
|
||||
manageAntennas: Hallitse antenneja
|
||||
info: Tietoja
|
||||
userInfo: Käyttäjätiedot
|
||||
unknown: Tuntematon
|
||||
onlineStatus: Online-tila
|
||||
hideOnlineStatus: Piilota Online-tila
|
||||
hideOnlineStatusDescription: Online-tilasi piilottaminen vähentää joidenkin toimintojen,
|
||||
kuten haun, käyttömukavuutta.
|
||||
online: Online
|
||||
active: Aktiivinen
|
||||
offline: Offline
|
||||
botProtection: Botti-suojaus
|
||||
instanceBlocking: Federaatio Esto/Hiljennys
|
||||
enabled: Otettu käyttöön
|
||||
quickAction: Pikatoiminnot
|
||||
user: Käyttäjä
|
||||
accounts: Tilit
|
||||
switch: Vaihda
|
||||
noBotProtectionWarning: Botti-suojausta ei ole konfiguroitu.
|
||||
configure: Konfiguroi
|
||||
postToGallery: Luo uusi galleriaviesti
|
||||
gallery: Galleria
|
||||
recentPosts: Viimeaikaiset sivut
|
||||
popularPosts: Suositut sivut
|
||||
ads: Mainokset
|
||||
expiration: Aikaraja
|
||||
memo: Muistio
|
||||
priority: Prioriteetti
|
||||
high: Korkea
|
||||
middle: Keskitaso
|
||||
low: Alhainen
|
||||
emailNotConfiguredWarning: Sähköpostiosoitetta ei ole asetettu.
|
||||
ratio: Suhde
|
||||
secureMode: Suojattu moodi (Valtuutettu nouto)
|
||||
instanceSecurity: Instanssiturvallisuus
|
||||
allowedInstancesDescription: Federaatiota varten sallitulle listalle (whitelisted)
|
||||
otettavien instanssien isännät, kukin erotettuna uudella rivillä (sovelletaan vain
|
||||
yksityisessä tilassa).
|
||||
previewNoteText: Näytä esikatselu
|
||||
customCss: Kustomoitu CSS
|
||||
customCssWarn: Tätä asetusta tulisi käyttää vain, jos tiedät, mitä se tekee. Vääränlaisten
|
||||
arvojen syöttäminen voi aiheuttaa sen, että asiakasohjelma lakkaa toimimasta normaalisti.
|
||||
recommended: Suositeltu
|
||||
squareAvatars: Näytä neliön malliset kuvakkeet
|
||||
seperateRenoteQuote: Erilliset buustaa ja lainaa -napit
|
||||
sent: Lähetetty
|
||||
useBlurEffect: Käytä blur-efektejä käyttöliittymässä
|
||||
misskeyUpdated: Firefish on päivitetty!
|
||||
whatIsNew: Näytä muutokset
|
||||
translate: Käännä
|
||||
translatedFrom: Käännetty kielestä {x}
|
||||
accountDeletionInProgress: Tilin poistaminen on parhaillaan menossa
|
||||
usernameInfo: Nimi, joka erottaa tilisi muista tällä palvelimella olevista tileistä. Voit
|
||||
käyttää aakkosia (a~z, A~Z), numeroita (0~9) tai alaviivoja (_). Käyttäjätunnuksia
|
||||
ei voi muuttaa myöhemmin.
|
||||
aiChanMode: Ai-chan klassisessa käyttöliittymässä
|
||||
keepCw: Pidä sisältövaroitukset
|
||||
pubSub: Pub/Sub tilit
|
||||
lastCommunication: Viimeisin kommunikaatio
|
||||
unresolved: Ratkaisematon
|
||||
breakFollow: Poista seuraaja
|
||||
breakFollowConfirm: Oletko varma, että haluat poistaa seuraajan?
|
||||
itsOn: Otettu käyttöön
|
||||
itsOff: Poistettu käytöstä
|
||||
emailRequiredForSignup: Vaadi sähköpostiosoitetta sisäänkirjautumiseen
|
||||
makeReactionsPublicDescription: Tämä laittaa viimeisimmät reaktiosi julkisesti näkyväksi.
|
||||
classic: Klassinen
|
||||
muteThread: Mykistä lanka
|
||||
unmuteThread: Poista langan mykistys
|
||||
ffVisibility: Seurataan/Seurattavien näkyvyys
|
||||
notRecommended: Ei suositeltu
|
||||
disabled: Poistettu käytöstä
|
||||
selectAccount: Valitse tili
|
||||
switchAccount: Vaihda tili
|
||||
administration: Hallinta
|
||||
shareWithNote: Jaa viestin kanssa
|
||||
secureModeInfo: Kun pyydät muista instansseista, älä lähetä takaisin ilman todisteita.
|
||||
privateMode: Yksityinen moodi
|
||||
privateModeInfo: Kun tämä on käytössä, vain sallittujen (whitelisted) luetteloon merkityt
|
||||
instanssit voivat liittyä instansseihisi. Kaikki viestit piilotetaan yleisöltä.
|
||||
global: Globaali
|
||||
resolved: Ratkaistu
|
||||
learnMore: Opi lisää
|
||||
continueThread: Jatka lankaa
|
||||
file: Tiedosto
|
||||
cropImageAsk: Haluatko rajata tätä kuvaa?
|
||||
recentNHours: Viimeiset {n} tuntia
|
||||
rateLimitExceeded: Nopeusraja ylittynyt
|
||||
cropImage: Rajaa kuvaa
|
||||
socialTimeline: Sosiaalinen aikajana
|
||||
themeColor: Instanssi Ticker Väri
|
||||
check: Tarkista
|
||||
ffVisibilityDescription: Antaa sinun konfiguroida, kuka voi nähdä ketä seuraat ja
|
||||
kuka seuraa sinua.
|
||||
homeTimeline: Koti aikajana
|
||||
size: Koko
|
||||
showLocalPosts: 'Näytä paikalliset viestit:'
|
||||
oneDay: Päivä
|
||||
instanceDefaultDarkTheme: Instanssikattava tumma oletusteema
|
||||
recentNDays: Viimeiset {n} päivää
|
||||
reflectMayTakeTime: Voi kestää jonkin aikaa, ennen kuin tämä näkyy.
|
||||
failedToFetchAccountInformation: Ei voitu hakea tietoja
|
||||
requireAdminForView: Sinun tulee kirjautua järjestelmänvalvojana nähdäksesi tämän.
|
||||
driveCapOverrideCaption: Resetoi oletusarvoon syöttämällä arvo 0 tai alempi.
|
||||
isSystemAccount: Järjestelmän luoma ja automaattisesti käyttämä tili.
|
||||
userSaysSomethingReasonReply: '{name} vastasi viestiin sisältäen {reason}'
|
||||
userSaysSomethingReasonRenote: '{name} buustasi viestiin sisältäen {reason}'
|
||||
voteConfirm: Vahvista äänesi vaihtoehdolle "{choice}"?
|
||||
hide: Piilota
|
||||
leaveGroup: Poistu ryhmästä
|
||||
leaveGroupConfirm: Oletko varma, että haluat poistua ryhmästä "{name}"?
|
||||
welcomeBackWithName: Tervetuloa takaisin, {name}
|
||||
clickToFinishEmailVerification: Klikkaa [{ok}] viimeistelläksesi sähköpostivahvistuksen.
|
||||
overridedDeviceKind: Laitetyyppi
|
||||
tablet: Tabletti
|
||||
numberOfColumn: Sarakkeiden määrä
|
||||
searchByGoogle: Etsi
|
||||
mutePeriod: Vaiennuksen kesto
|
||||
indefinitely: Pysyvästi
|
||||
tenMinutes: 10 minuuttia
|
||||
oneHour: Tunti
|
||||
thereIsUnresolvedAbuseReportWarning: On ratkaisemattomia raportteja.
|
||||
driveCapOverrideLabel: Muuta aseman kapasiteetti tälle käyttäjälle
|
||||
userSaysSomethingReasonQuote: '{name} lainasi viestiä sisältäen {reason}'
|
||||
deleteAccountConfirm: Tämä peruuttamattomasti poistaa tilisi. Jatketaanko?
|
||||
incorrectPassword: Väärä salasana.
|
||||
useDrawerReactionPickerForMobile: Näytä reaktiovalitsin mobiilissa laatikkomallisena
|
||||
smartphone: Älypuhelin
|
||||
auto: Automaattinen
|
||||
oneWeek: Viikko
|
||||
instanceDefaultLightTheme: Instanssin kattava vaalea oletusteema
|
||||
instanceDefaultThemeDescription: Anna teemakoodi objektiformaatille.
|
||||
noEmailServerWarning: Sähköpostipalvelinta ei konfiguroituna.
|
2039
locales/fr-FR.yml
Normal file
2039
locales/fr-FR.yml
Normal file
File diff suppressed because it is too large
Load diff
17
locales/gl.yml
Normal file
17
locales/gl.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
_lang_: Inglés
|
||||
introMisskey: Benvida! Firefish é unha plataforma de medios sociais de código aberto,
|
||||
descentralizada e gratuíta para sempre!🚀
|
||||
monthAndDay: '{day}/{month}'
|
||||
notifications: Notificacións
|
||||
password: Contrasinal
|
||||
forgotPassword: Esquecín o contrasinal
|
||||
gotIt: Vale!
|
||||
cancel: Cancelar
|
||||
noThankYou: Non, grazas
|
||||
headlineMisskey: Plataforma de medios sociais de código aberto e descentralizada,
|
||||
gratuíta para sempre!🚀
|
||||
search: Buscar
|
||||
searchPlaceholder: Buscar en Firefish
|
||||
username: Identificador
|
||||
fetchingAsApObject: Descargando desde o Fediverso
|
||||
ok: OK
|
1792
locales/id-ID.yml
Normal file
1792
locales/id-ID.yml
Normal file
File diff suppressed because it is too large
Load diff
3
locales/index.d.ts
vendored
Normal file
3
locales/index.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
declare const locales: { [lang: string]: any };
|
||||
|
||||
export = locales;
|
91
locales/index.js
Normal file
91
locales/index.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* Languages Loader
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const yaml = require("js-yaml");
|
||||
const languages = [];
|
||||
const languages_custom = [];
|
||||
|
||||
const merge = (...args) =>
|
||||
args.reduce(
|
||||
(a, c) => ({
|
||||
...a,
|
||||
...c,
|
||||
...Object.entries(a)
|
||||
.filter(([k]) => c && typeof c[k] === "object")
|
||||
.reduce((a, [k, v]) => ((a[k] = merge(v, c[k])), a), {}),
|
||||
}),
|
||||
{},
|
||||
);
|
||||
|
||||
fs.readdirSync(__dirname).forEach((file) => {
|
||||
if (file.includes(".yml")) {
|
||||
file = file.slice(0, file.indexOf("."));
|
||||
languages.push(file);
|
||||
}
|
||||
});
|
||||
|
||||
fs.readdirSync(__dirname + "/../custom/locales").forEach((file) => {
|
||||
if (file.includes(".yml")) {
|
||||
file = file.slice(0, file.indexOf("."));
|
||||
languages_custom.push(file);
|
||||
}
|
||||
});
|
||||
|
||||
const primaries = {
|
||||
en: "US",
|
||||
ja: "JP",
|
||||
zh: "CN",
|
||||
};
|
||||
|
||||
// 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く
|
||||
const clean = (text) =>
|
||||
text.replace(new RegExp(String.fromCodePoint(0x08), "g"), "");
|
||||
|
||||
const locales = languages.reduce(
|
||||
(a, c) => (
|
||||
(a[c] =
|
||||
yaml.load(clean(fs.readFileSync(`${__dirname}/${c}.yml`, "utf-8"))) ||
|
||||
{}),
|
||||
a
|
||||
),
|
||||
{},
|
||||
);
|
||||
const locales_custom = languages_custom.reduce(
|
||||
(a, c) => (
|
||||
(a[c] =
|
||||
yaml.load(
|
||||
clean(
|
||||
fs.readFileSync(`${__dirname}/../custom/locales/${c}.yml`, "utf-8"),
|
||||
),
|
||||
) || {}),
|
||||
a
|
||||
),
|
||||
{},
|
||||
);
|
||||
Object.assign(locales, locales_custom);
|
||||
|
||||
module.exports = Object.entries(locales).reduce(
|
||||
(a, [k, v]) => (
|
||||
(a[k] = (() => {
|
||||
const [lang] = k.split("-");
|
||||
switch (k) {
|
||||
case "ja-JP":
|
||||
return v;
|
||||
case "ja-KS":
|
||||
case "en-US":
|
||||
return merge(locales["ja-JP"], v);
|
||||
default:
|
||||
return merge(
|
||||
locales["ja-JP"],
|
||||
locales["en-US"],
|
||||
locales[`${lang}-${primaries[lang]}`] || {},
|
||||
v,
|
||||
);
|
||||
}
|
||||
})()),
|
||||
a
|
||||
),
|
||||
{},
|
||||
);
|
1563
locales/it-IT.yml
Normal file
1563
locales/it-IT.yml
Normal file
File diff suppressed because it is too large
Load diff
1961
locales/ja-JP.yml
Normal file
1961
locales/ja-JP.yml
Normal file
File diff suppressed because it is too large
Load diff
1415
locales/ja-KS.yml
Normal file
1415
locales/ja-KS.yml
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue