Merge branch 'develop' into gh-fa55fa5e/10452/unknown/rtl
|
@ -192,6 +192,9 @@ reservedUsernames: [
|
|||
# Proxy remote files (default: false)
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
# Use authorized fetch for outgoing requests
|
||||
signToActivityPubGet: true
|
||||
|
||||
#allowedPrivateNetworks: [
|
||||
# '127.0.0.1/32'
|
||||
#]
|
||||
|
|
3
.gitignore
vendored
|
@ -57,6 +57,9 @@ packages/backend/assets/LICENSE
|
|||
!/packages/backend/src/db
|
||||
!/packages/backend/src/server/api/endpoints/drive/files
|
||||
|
||||
packages/megalodon/lib
|
||||
packages/megalodon/.idea
|
||||
|
||||
# blender backups
|
||||
*.blend1
|
||||
*.blend2
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
v18.16.0
|
1
.npmrc
|
@ -1 +0,0 @@
|
|||
use-lockfile-v6=true
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/vsls",
|
||||
"gitignore": "exclude"
|
||||
}
|
2098
CHANGELOG.md
|
@ -94,9 +94,9 @@ An actual domain will be assigned so you can test the federation.
|
|||
- The tag name must be the version
|
||||
|
||||
## Development
|
||||
During development, it is useful to use the `yarn dev` command.
|
||||
During development, it is useful to use the `pnpm run 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.
|
||||
In addition, it will also automatically start the Firefish server process.
|
||||
|
||||
## Testing
|
||||
- Test codes are located in [`/test`](/test).
|
||||
|
@ -119,20 +119,13 @@ 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
|
||||
TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT="./test/tsconfig.json" pnpx 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.
|
||||
Firefish 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.**
|
||||
- **When creating a new component, please use the Composition API (with [setup syntax](https://v3.vuejs.org/api/sfc-script-setup.html) and [ref syntax](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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
## Install dev and compilation dependencies, build files
|
||||
FROM node:latest as build
|
||||
FROM node:20-slim as build
|
||||
WORKDIR /firefish
|
||||
|
||||
# Install compilation dependencies
|
||||
|
@ -26,6 +26,7 @@ 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
|
||||
|
@ -47,14 +48,16 @@ RUN env NODE_ENV=production sh -c "pnpm run --filter '!native-utils' build && pn
|
|||
RUN pnpm i --prod --frozen-lockfile
|
||||
|
||||
## Runtime container
|
||||
FROM node:latest
|
||||
FROM node:20-slim
|
||||
WORKDIR /firefish
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y libvips-dev zip unzip tini ffmpeg
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends libvips-dev zip unzip tini ffmpeg
|
||||
|
||||
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
|
||||
|
|
|
@ -98,11 +98,11 @@ url: "https://{{ .Values.firefish.domain }}/"
|
|||
#───┘ Port and TLS settings └───────────────────────────────────
|
||||
|
||||
#
|
||||
# Misskey requires a reverse proxy to support HTTPS connections.
|
||||
# Firefish requires a reverse proxy to support HTTPS connections.
|
||||
#
|
||||
# +----- https://example.tld/ ------------+
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# | User | ---> || Proxy (443) | ---> | Misskey (3000) ||
|
||||
# | User | ---> || Proxy (443) | ---> | Firefish (3000) ||
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# +---------------------------------------+
|
||||
#
|
||||
|
@ -110,7 +110,7 @@ url: "https://{{ .Values.firefish.domain }}/"
|
|||
# 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.
|
||||
# The port that your Firefish server should listen on.
|
||||
port: 3000
|
||||
|
||||
# ┌──────────────────────────┐
|
||||
|
|
|
@ -139,10 +139,10 @@ describe("After user singed in", () => {
|
|||
|
||||
it("note", () => {
|
||||
cy.get("[data-cy-open-post-form]").click();
|
||||
cy.get("[data-cy-post-form-text]").type("Hello, Misskey!");
|
||||
cy.get("[data-cy-post-form-text]").type("Hello, Firefish!");
|
||||
cy.get("[data-cy-open-post-form-submit]").click();
|
||||
|
||||
cy.contains("Hello, Misskey!");
|
||||
cy.contains("Hello, Firefish!");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -2,7 +2,9 @@ version: "3"
|
|||
|
||||
services:
|
||||
web:
|
||||
image: registry.joinfirefish.org/firefish/firefish
|
||||
# Choose one of these tags:
|
||||
# stable-amd64, stable-arm64, beta-amd64, beta-arm64
|
||||
image: registry.joinfirefish.org/firefish/firefish:stable-amd64
|
||||
container_name: firefish_web
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
|
|
|
@ -4,6 +4,11 @@ Breaking changes are indicated by the :warning: icon.
|
|||
|
||||
## v1.0.5 (unreleased)
|
||||
|
||||
### dev21
|
||||
|
||||
- `admin/update-meta` can now take `moreUrls` parameter, and response of `admin/meta` now includes `moreUrls`
|
||||
- These URLs are used for the help menu ([related merge request](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10640))
|
||||
|
||||
### dev18
|
||||
|
||||
- :warning: response of `meta` no longer includes the following:
|
||||
|
|
|
@ -52,7 +52,7 @@ gulp.task("build:backend:script", () => {
|
|||
"./packages/backend/src/server/web/bios.js",
|
||||
"./packages/backend/src/server/web/cli.js",
|
||||
])
|
||||
.pipe(replace("LANGS", JSON.stringify(Object.keys(locales))))
|
||||
.pipe(replace("SUPPORTED_LANGS", JSON.stringify(Object.keys(locales))))
|
||||
.pipe(
|
||||
terser({
|
||||
toplevel: true,
|
||||
|
|
|
@ -475,3 +475,5 @@ _preferencesBackups:
|
|||
editWidgetsExit: Готово
|
||||
done: Готово
|
||||
emailRequiredForSignup: Изискване за адрес на е-поща за регистриране
|
||||
preview: Преглед
|
||||
privacy: Поверителност
|
||||
|
|
|
@ -112,7 +112,7 @@ you: "Tu"
|
|||
clickToShow: "Fes clic per a mostrar"
|
||||
sensitive: "NSFW"
|
||||
add: "Afegeix"
|
||||
reaction: "Reaccions"
|
||||
reaction: "Reacció"
|
||||
reactionSetting: "Reaccions a mostrar al selector de reaccions"
|
||||
reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem
|
||||
\"+\" per afegir."
|
||||
|
@ -792,11 +792,11 @@ customEmojis: Emojis personalitzats
|
|||
cacheRemoteFilesDescription: Quan aquesta opció està desactivada, els fitxers remots
|
||||
es carreguen directament del servidor remot. Desactivar-la farà que baixi l'ús d'emmagatzematge,
|
||||
però incrementa el tràfic, perquè les miniatures no es generaran.
|
||||
flagAsBot: Marca aquest compte com a bot
|
||||
flagAsBot: Marca aquest compte com automatitzat
|
||||
flagAsBotDescription: Activa aquesta opció si aquest compte és controlat per un programa.
|
||||
Si s'activa, això actuarà com una bandera per a altres desenvolupadors i ajuda a
|
||||
prevenir cadenes de interaccions infinites amb altres bots a més d'ajustar els sistemes
|
||||
interns de Firefish per tractar aquest compte com un bot.
|
||||
prevenir cadenes de interaccions infinites amb altres comptes automatitzats a més
|
||||
d'ajustar els sistemes interns de Firefish per tractar aquest compte com automatitzat.
|
||||
flagAsCat: Ets un gat? 🐱
|
||||
flagShowTimelineReplies: Mostra respostes a la línia de temps
|
||||
flagAsCatDescription: Guanyaràs unes orelles de gat i parlares com un gat!
|
||||
|
@ -895,7 +895,7 @@ nUsersRead: llegit per {n}
|
|||
agreeTo: Estic d'acord amb {0}
|
||||
activity: Activitat
|
||||
home: Inici
|
||||
remoteUserCaution: La informació dels usuaris remots pot estar incompleta.
|
||||
remoteUserCaution: La informació dels usuaris remots és incompleta.
|
||||
themeForDarkMode: Tema a fer servir en mode fosc
|
||||
light: Clar
|
||||
registeredDate: Data de registre
|
||||
|
@ -1051,7 +1051,7 @@ popularTags: Etiquetes populars
|
|||
about: Sobre
|
||||
recentlyUpdatedUsers: Usuaris actius fa poc
|
||||
recentlyRegisteredUsers: Usuaris registrats fa poc
|
||||
recentlyDiscoveredUsers: Nous suaris descoberts
|
||||
recentlyDiscoveredUsers: Nous usuaris descoberts
|
||||
administrator: Administrador
|
||||
token: Token
|
||||
registerSecurityKey: Registreu una clau de seguretat
|
||||
|
@ -1550,7 +1550,7 @@ troubleshooting: Resolució de problemes
|
|||
learnMore: Més informació
|
||||
misskeyUpdated: Firefish s'ha actualitzat!
|
||||
translate: Tradueix
|
||||
translatedFrom: Traduït desde {x}
|
||||
translatedFrom: Traduït del {x}
|
||||
aiChanMode: Ai-chan a la interfície d'usuari clàssica
|
||||
keepCw: Mantenir els avisos de contingut
|
||||
pubSub: Comptes Pub/Sub
|
||||
|
@ -2127,7 +2127,7 @@ clipsDesc: Els clips són com marcadors categoritzats que es poden compartir. Po
|
|||
selectChannel: Selecciona un canal
|
||||
isLocked: Aquest compte té les següents aprovacions
|
||||
isPatron: Mecenes de Firefish
|
||||
isBot: Aquest compte és un bot
|
||||
isBot: Aquest es un compte automatitzat
|
||||
isModerator: Moderador
|
||||
isAdmin: Administrador
|
||||
_filters:
|
||||
|
@ -2199,3 +2199,22 @@ openServerInfo: Mostra la informació del servidor fent clic al símbol del serv
|
|||
en un missatge
|
||||
vibrate: Activar vibracions
|
||||
clickToShowPatterns: Fes clic per veure patrons de mòduls
|
||||
iconSet: Conjunt d'Icones
|
||||
_iconSets:
|
||||
fill: Omplerts
|
||||
regular: Normals
|
||||
bold: Negreta
|
||||
duotone: Bitó
|
||||
light: Prims
|
||||
showAttachedNotes: Mostrar publicacions que contenen aquest fitxer
|
||||
reactions: Reaccions
|
||||
attachedToNotes: Publicacions que contenen aquest fitxer
|
||||
replies: Respostes
|
||||
quotes: Cites
|
||||
renotes: Impulsos
|
||||
moreUrls: Pàgines fixades
|
||||
moreUrlsDescription: "Introdueix les pàgines que vols fixar al menú d'ajuda a la part
|
||||
inferior esquerra fent servir aquesta notació:\n\"Nom a mostrar\": https://example.com/"
|
||||
useEmojiCdn: Aconsegueix Twemoji des d'un CDN
|
||||
useEmojiCdnDescription: Fes servir Twemoji des del CDN de JSDeliver en lloc de fer
|
||||
servir el del propi servidor.
|
||||
|
|
|
@ -402,6 +402,8 @@ withReplies: "Antworten beinhalten"
|
|||
connectedTo: "Mit folgenden Nutzerkonten verknüpft"
|
||||
notesAndReplies: "Beiträge und Antworten"
|
||||
withFiles: "Beiträge mit Dateien"
|
||||
attachedToNotes: "Beiträge mit dieser Datei"
|
||||
showAttachedNotes: "Zeige Beiträge mit dieser Datei"
|
||||
silence: "stummschalten"
|
||||
silenceConfirm: "Sind Sie sicher, dass Sie diesen Benutzer Stummschalten möchten?"
|
||||
unsilence: "Stummschaltung aufheben"
|
||||
|
@ -2216,3 +2218,4 @@ openServerInfo: Anzeigen von Serverinformationen durch Anklicken des Server-Tick
|
|||
in einem Beitrag
|
||||
vibrate: Vibrationen abspielen
|
||||
clickToShowPatterns: Klicken um Modul-Muster anzuzeigen
|
||||
replies: Antworten
|
||||
|
|
|
@ -168,11 +168,11 @@ cacheRemoteFiles: "Cache remote files"
|
|||
cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded
|
||||
directly from the remote server. Disabling this will decrease storage usage, but
|
||||
increase traffic, as thumbnails will not be generated."
|
||||
flagAsBot: "Mark this account as a bot"
|
||||
flagAsBot: "Mark this account as automated"
|
||||
flagAsBotDescription: "Enable this option if this account is controlled by a program.
|
||||
If enabled, it will act as a flag for other developers to prevent endless interaction
|
||||
chains with other bots and adjust Firefish's internal systems to treat this account
|
||||
as a bot."
|
||||
chains with other automated accounts and adjust Firefish's internal systems to treat this
|
||||
account as an automated account."
|
||||
flagAsCat: "Are you a cat? 😺"
|
||||
flagAsCatDescription: "You'll get cat ears and speak like a cat!"
|
||||
flagSpeakAsCat: "Speak as a cat"
|
||||
|
@ -312,7 +312,7 @@ agreeTo: "I agree to {0}"
|
|||
tos: "Terms of Service"
|
||||
start: "Begin"
|
||||
home: "Home"
|
||||
remoteUserCaution: "Information from remote users may be incomplete."
|
||||
remoteUserCaution: "Information from remote users are incomplete."
|
||||
activity: "Activity"
|
||||
images: "Images"
|
||||
birthday: "Birthday"
|
||||
|
@ -429,6 +429,8 @@ withReplies: "Include replies"
|
|||
connectedTo: "Following account(s) are connected"
|
||||
notesAndReplies: "Posts and replies"
|
||||
withFiles: "Including files"
|
||||
attachedToNotes: "Posts with this file"
|
||||
showAttachedNotes: "Show posts with this file"
|
||||
silence: "Silence"
|
||||
silenceConfirm: "Are you sure that you want to silence this user?"
|
||||
unsilence: "Undo silencing"
|
||||
|
@ -1115,7 +1117,7 @@ noGraze: "Please disable the \"Graze for Mastodon\" browser extension, as it int
|
|||
with Firefish."
|
||||
silencedWarning: "This page is showing because these users are from servers your admin
|
||||
silenced, so they may potentially be spam."
|
||||
isBot: "This account is a bot"
|
||||
isBot: "This account is automated"
|
||||
isLocked: "This account has follow approvals"
|
||||
isModerator: "Moderator"
|
||||
isAdmin: "Administrator"
|
||||
|
@ -1154,6 +1156,8 @@ detectPostLanguage: "Automatically detect the language and show a translate butt
|
|||
vibrate: "Play vibrations"
|
||||
openServerInfo: "Show server information by clicking the server ticker on a post"
|
||||
iconSet: "Icon set"
|
||||
useEmojiCdn: "Get Twemoji from CDN"
|
||||
useEmojiCdnDescription: "Use Twemoji from the JSDelivr CDN instead of the server's assets."
|
||||
|
||||
_sensitiveMediaDetection:
|
||||
description: "Reduces the effort of server moderation through automatically recognizing
|
||||
|
@ -2159,3 +2163,5 @@ _iconSets:
|
|||
regular: "Regular"
|
||||
fill: "Filled"
|
||||
duotone: "Duotone"
|
||||
moreUrls: "Pinned pages"
|
||||
moreUrlsDescription: "Enter the pages you want to pin to the help menu in the lower left corner using this notation:\n\"Display name\": https://example.com/"
|
||||
|
|
|
@ -1219,6 +1219,13 @@ _wordMute:
|
|||
soft: "Suave"
|
||||
hard: "Duro"
|
||||
mutedNotes: "Publicaciones silenciadas"
|
||||
muteLangsDescription2: 'Utilizar códigos de idioma, por ejemplo: en, fr, ja, zh.'
|
||||
lang: Idioma
|
||||
langDescription: Ocultar publicaciones de linea de tiempo que coincidan con el idioma
|
||||
seleccionado.
|
||||
muteLangs: Idiomas silenciados
|
||||
muteLangsDescription: Separar con espacios o saltos de lineas para una condición
|
||||
OR
|
||||
_instanceMute:
|
||||
instanceMuteDescription: "Silencia todas las publicaciones e impusos de los servidores
|
||||
seleccionados, incluyendo respuestas a los usuarios de las mismas."
|
||||
|
@ -2162,3 +2169,15 @@ silencedWarning: Esta página se muestra debido a que estos usuarios son de serv
|
|||
que tu administrador ha silenciado, ya que son presumiblemente fuente de spam.
|
||||
isBot: Esta cuenta es un bot
|
||||
clickToShowPatterns: Haz clic para mostrar patrones de módulos
|
||||
detectPostLanguage: Detectar automáticamente el idioma y mostrar el botón de traducción
|
||||
para publicaciones en otros idiomas
|
||||
indexableDescription: Permitir que el buscador integrado muestre tus publicaciones
|
||||
reactions: Reacciones
|
||||
exportZip: Exportar ZIP
|
||||
emojiPackCreator: Creador de pack de Emoji
|
||||
importZip: Importar ZIP
|
||||
vibrate: Reproducir vibraciones
|
||||
openServerInfo: Mostrar información del servidor al presionar el simbolo del servidor
|
||||
en una publicación
|
||||
languageForTranslation: Traducción de publicaciones
|
||||
confirm: Confirmar
|
||||
|
|
|
@ -114,7 +114,7 @@ you: "Vous"
|
|||
clickToShow: "Cliquer pour afficher"
|
||||
sensitive: "Contenu sensible"
|
||||
add: "Ajouter"
|
||||
reaction: "Réactions"
|
||||
reaction: "Réaction"
|
||||
reactionSetting: "Réactions à afficher dans le sélecteur de réactions"
|
||||
reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser
|
||||
« + » pour ajouter."
|
||||
|
@ -1148,7 +1148,7 @@ _wordMute:
|
|||
langDescription: Cacher du fil de publication les publications qui correspondent
|
||||
à ces langues.
|
||||
muteLangs: Langages filtrés
|
||||
muteLangsDescription: Séparer avec des espaces or des retours à la ligne pour une
|
||||
muteLangsDescription: Séparer avec des espaces ou des retours à la ligne pour une
|
||||
condition OU (OR).
|
||||
_instanceMute:
|
||||
instanceMuteDescription2: "Séparer avec des sauts de lignes"
|
||||
|
@ -2225,3 +2225,14 @@ indexable: Indexable
|
|||
languageForTranslation: Langage post-traduction
|
||||
vibrate: Jouer les vibrations
|
||||
clickToShowPatterns: Cliquer pour montrer les patrons de modules
|
||||
iconSet: Jeu d'icônes
|
||||
_iconSets:
|
||||
fill: Rempli
|
||||
regular: Normal
|
||||
bold: Gras
|
||||
duotone: Deux tons
|
||||
light: Fin
|
||||
reactions: Réactions
|
||||
replies: Réponses
|
||||
quotes: Citations
|
||||
renotes: Boosts
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
_lang_: Inglés
|
||||
_lang_: Galego
|
||||
introFirefish: Benvida! Firefish é unha plataforma de medios sociais de código aberto,
|
||||
descentralizada e gratuíta para sempre!🚀
|
||||
monthAndDay: '{day}/{month}'
|
||||
|
|
|
@ -148,11 +148,11 @@ cacheRemoteFiles: "Tembolokkan berkas remote"
|
|||
cacheRemoteFilesDescription: "Ketika pengaturan ini dinonaktifkan, berkas luar akan
|
||||
dimuat langsung dari server luar. Menonaktifkan ini akan mengurangi penggunaan penyimpanan,
|
||||
tapi dapat menyebabkan meningkatkan lalu lintas, mengingat keluku tidak akan dihasilkan."
|
||||
flagAsBot: "Atur akun ini sebagai Bot"
|
||||
flagAsBotDescription: "Jika akun ini dikendalikan oleh program, tetapkanlah opsi ini.
|
||||
flagAsBot: "Tandai akun ini sebagai akun otomatis"
|
||||
flagAsBotDescription: "Jika akun ini dikendalikan oleh program, aktifkan opsi ini.
|
||||
Jika diaktifkan, ini akan berfungsi sebagai tanda bagi pengembang lain untuk mencegah
|
||||
interaksi berantai dengan bot lain dan menyesuaikan sistem internal Firefish untuk
|
||||
memperlakukan akun ini sebagai bot."
|
||||
interaksi berantai dengan akun otomatis lain dan menyesuaikan sistem internal Firefish
|
||||
untuk memperlakukan akun ini sebagai akun otomatis."
|
||||
flagAsCat: "Atur akun ini sebagai kucing"
|
||||
flagAsCatDescription: "Kamu akan mendapatkan telinga kucing dan berbicara seperti
|
||||
seekor kucing!"
|
||||
|
@ -278,8 +278,7 @@ agreeTo: "Saya setuju kepada {0}"
|
|||
tos: "Syarat dan ketentuan"
|
||||
start: "Mulai"
|
||||
home: "Beranda"
|
||||
remoteUserCaution: "Informasi ini mungkin tidak mutakhir, karena pengguna ini berasal
|
||||
dari instansi luar."
|
||||
remoteUserCaution: "Informasi dari pengguna luar tidak lengkap."
|
||||
activity: "Aktivitas"
|
||||
images: "Gambar"
|
||||
birthday: "Tanggal lahir"
|
||||
|
@ -2005,7 +2004,7 @@ signupsDisabled: Pendaftaran ke server ini nonaktif, tapi kamu dapat selalu mend
|
|||
ke server lain! Jika kamu memiliki kode undangan server ini, harap masukkan di bawah
|
||||
ini.
|
||||
enableCustomKaTeXMacro: Aktifkan makro KaTeX khusus
|
||||
isBot: Akun ini bot
|
||||
isBot: Akun ini akun otomatis
|
||||
customMOTD: MOTD khusus (pesan layar percik)
|
||||
recommendedInstancesDescription: Server yang direkomendasikan dipisahkan dengan garis
|
||||
baru untuk tampil di linimasa rekomendasi.
|
||||
|
@ -2181,3 +2180,21 @@ openServerInfo: Tampilkan informasi server dengan mengeklik ticker server di seb
|
|||
kiriman
|
||||
vibrate: Putar getaran
|
||||
clickToShowPatterns: Klik untuk menampilkan pola modul
|
||||
iconSet: Set ikon
|
||||
_iconSets:
|
||||
fill: Penuh
|
||||
regular: Reguler
|
||||
bold: Tebal
|
||||
duotone: Duotone
|
||||
light: Tipis
|
||||
reactions: Reaksi
|
||||
replies: Balasan
|
||||
quotes: Kutipan
|
||||
renotes: Postingan ulang
|
||||
showAttachedNotes: Tampilkan postingan dengan berkas ini
|
||||
attachedToNotes: Posting dengan berkas ini
|
||||
moreUrls: Halaman tersemat
|
||||
moreUrlsDescription: "Masukkan halaman yang ingin kamu sematkan ke menu bantuan di
|
||||
pojok kiri bawah dengan notasi ini:\n\"Nama tampilan\": https://contoh.com/"
|
||||
useEmojiCdn: Dapatkan Twemoji dari CDN
|
||||
useEmojiCdnDescription: Gunakan Twemoji dari JSDelv CDN bukan dari aset server.
|
||||
|
|
|
@ -147,11 +147,11 @@ cacheRemoteFiles: "Mantieni i file remoti nella cache"
|
|||
cacheRemoteFilesDescription: "Disabilitando questa opzione, i file remoti verranno
|
||||
scaricati direttamente dal loro server. L'opzione permette di risparmiare spazio
|
||||
ma aumenta il traffico di rete e non verranno generate anteprime."
|
||||
flagAsBot: "Questo account è un bot"
|
||||
flagAsBot: "Questo account è automatizzato"
|
||||
flagAsBotDescription: "Se l'account esegue principalmente operazioni automatiche,
|
||||
attiva quest'opzione. Quando attivata, opera come un segnalatore per gli altri sviluppatori
|
||||
allo scopo di prevenire catene d’interazione senza fine con altri bot, e di adeguare
|
||||
i sistemi interni di Firefish perché trattino questo account come un bot."
|
||||
attiva quest'opzione. Quando attivata, permette agli sviluppatori di prevenire catene
|
||||
d’interazione senza fine con altri account automatizzati. Inoltre imposta Firefish
|
||||
perché tratti questo account come automatizzato."
|
||||
flagAsCat: "Sei un gatto? 😺"
|
||||
flagAsCatDescription: "Ti compariranno le orecchie e parlerai come un gatto!"
|
||||
autoAcceptFollowed: "Accetta in automatico i follow dagli account che segui"
|
||||
|
@ -268,7 +268,7 @@ agreeTo: "Sono d'accordo con {0}"
|
|||
tos: "Termini d'uso"
|
||||
start: "Inizia"
|
||||
home: "Home"
|
||||
remoteUserCaution: "Le informazioni degli utenti remoti possono essere incomplete."
|
||||
remoteUserCaution: "Le informazioni degli utenti remoti sono incomplete."
|
||||
activity: "Attività"
|
||||
images: "Immagini"
|
||||
birthday: "Compleanno"
|
||||
|
@ -2079,7 +2079,7 @@ noGraze: Per favore disattiva l'estenzione del browser "Graze for Mastodon", per
|
|||
interferisce con Firefish.
|
||||
silencedWarning: Vedi questa pagina perché gli utenti sono su un server che il tuo
|
||||
admin ha silenziato, quindi potrebbero essere spam.
|
||||
isBot: Questo account è un bot
|
||||
isBot: Questo account è automatizzato
|
||||
isLocked: Serve una approvazione per seguire questo account
|
||||
moveFromDescription: Questa operazione crea un alias del vecchio account in modo che
|
||||
tu possa migrare su questo nuovo account. Fallo PRIMA di migrare il tuo vecchio
|
||||
|
@ -2169,3 +2169,21 @@ openServerInfo: Mostra informazioni sul server cliccando sul riquadro del server
|
|||
un post
|
||||
vibrate: Abilita la vibrazione
|
||||
clickToShowPatterns: Clicca per vedere i pattern del modulo
|
||||
iconSet: Set di icone
|
||||
_iconSets:
|
||||
fill: Con riempimento
|
||||
regular: Regolare
|
||||
bold: Grassetto
|
||||
duotone: Con due toni
|
||||
light: Sottile
|
||||
reactions: Reazioni
|
||||
replies: Risposte
|
||||
quotes: Citazioni
|
||||
renotes: Boost
|
||||
showAttachedNotes: Mostra i post con questo allegato
|
||||
attachedToNotes: Post con questo allegato
|
||||
moreUrls: Pagine del menu di aiuto
|
||||
moreUrlsDescription: "Inserisci con questo formato le pagine che vuoi aggiungere al
|
||||
menu di aiuto nell'angolo in basso a sinistra:\n\"Nome link\": https://example.com/"
|
||||
useEmojiCdn: Scarica Twemoji da CDN
|
||||
useEmojiCdnDescription: Usa Twemoji dalla CDN di JSDelivr invece che dal server locale.
|
||||
|
|
|
@ -149,8 +149,8 @@ addEmoji: "絵文字を追加"
|
|||
settingGuide: "おすすめ設定"
|
||||
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
||||
cacheRemoteFilesDescription: "この設定を無効にすると、リモートファイルをキャッシュせず直リンクします。サーバーのストレージを節約できますが、サムネイルが生成されないので通信量が増加します。"
|
||||
flagAsBot: "Botとして設定"
|
||||
flagAsBotDescription: "このアカウントがBotである場合は、この設定をオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Firefishのシステム上での扱いがBotに合ったものになります。"
|
||||
flagAsBot: "自動化されたアカウントとして設定"
|
||||
flagAsBotDescription: "このアカウントが自動で投稿する場合は、この設定をオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Firefishのシステム上での扱いが自動で投稿するアカウントに合ったものになります。"
|
||||
flagAsCat: "あなたは…猫?😺"
|
||||
flagAsCatDescription: "このアカウントが猫であることを示す猫モードを有効にするには、このフラグをオンにします。"
|
||||
flagSpeakAsCat: "猫語で話す"
|
||||
|
@ -384,6 +384,8 @@ withReplies: "返信を含む"
|
|||
connectedTo: "次のアカウントに接続されています"
|
||||
notesAndReplies: "投稿と返信"
|
||||
withFiles: "ファイル付き"
|
||||
attachedToNotes: "このファイルが添付された投稿"
|
||||
showAttachedNotes: "このファイルが添付された投稿を見る"
|
||||
silence: "サイレンス"
|
||||
silenceConfirm: "サイレンスしますか?"
|
||||
unsilence: "サイレンス解除"
|
||||
|
@ -979,7 +981,7 @@ customKaTeXMacroDescription: "数式入力を楽にするためのマクロを
|
|||
が 3 + foo に展開されます。また、マクロの名前を囲む波括弧を丸括弧 () および角括弧 [] に変更した場合、マクロの引数に使用する括弧が変更されます。マクロの定義は一行に一つのみで、途中で改行はできません。マクロの定義が無効な行は無視されます。文字列を単純に置換する機能のみに対応していて、条件分岐などの高度な構文は使用できません。"
|
||||
enableCustomKaTeXMacro: "カスタムKaTeXマクロを有効にする"
|
||||
preventAiLearning: "AIによる学習を防止"
|
||||
preventAiLearningDescription: "投稿したノート、添付した画像などのコンテンツを学習の対象にしないようAIに要求します。これはnoaiフラグをHTMLレスポンスに含めることによって実現されます。"
|
||||
preventAiLearningDescription: "投稿した文章や、添付した画像などのコンテンツを学習の対象にしないようAIに要求します。これはnoaiフラグをHTMLレスポンスに含めることによって実現されます。"
|
||||
noGraze: "ブラウザの拡張機能「Graze for Mastodon」は、Firefishの動作を妨げるため、無効にしてください。"
|
||||
enableServerMachineStats: "サーバーのマシン情報を公開する"
|
||||
enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする"
|
||||
|
@ -992,6 +994,8 @@ addRe: "閲覧注意の投稿への返信で、注釈の先頭に\"re:\"を追
|
|||
languageForTranslation: "投稿翻訳に使用する言語"
|
||||
detectPostLanguage: "投稿の言語を自動検出し、外国語の投稿に翻訳ボタンを表示する"
|
||||
iconSet: "アイコンのスタイル"
|
||||
useEmojiCdn: "CDNのTwemojiを利用する"
|
||||
useEmojiCdnDescription: "サーバー上に保存されているTwemojiのアセットの代わりに、JSDelivr CDNから配信されたものを用います。"
|
||||
|
||||
_sensitiveMediaDetection:
|
||||
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てられます。サーバーの負荷が少し増えます。"
|
||||
|
@ -1029,7 +1033,7 @@ _ad:
|
|||
_forgotPassword:
|
||||
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"
|
||||
ifNoEmail: "メールアドレスを登録していない場合は、管理者までお問い合わせください。"
|
||||
contactAdmin: "このインスタンスではメールアドレスの登録がサポートされていないため、パスワードリセットを行う場合は管理者までお問い合わせください。"
|
||||
contactAdmin: "このサーバーではメールアドレスの登録がサポートされていないため、パスワードリセットを行う場合は管理者までお問い合わせください。"
|
||||
_gallery:
|
||||
my: "自分の投稿"
|
||||
liked: "いいねした投稿"
|
||||
|
@ -1954,7 +1958,7 @@ isModerator: モデレーター
|
|||
audio: 音声
|
||||
image: 画像
|
||||
video: 動画
|
||||
isBot: このアカウントはBotです
|
||||
isBot: このアカウントは自動で投稿します
|
||||
isLocked: このアカウントのフォローは承認制です
|
||||
isAdmin: 管理者
|
||||
isPatron: Firefish 後援者
|
||||
|
@ -2001,3 +2005,5 @@ _iconSets:
|
|||
regular: "標準"
|
||||
fill: "塗りつぶし"
|
||||
duotone: "2色"
|
||||
moreUrls: "固定するページ"
|
||||
moreUrlsDescription: "左下のヘルプメニューに固定したいページを以下の形式で、改行区切りで入力してください:\n\"表示名\": https://example.com/"
|
||||
|
|
|
@ -714,7 +714,7 @@ registry: "レジストリ"
|
|||
closeAccount: "このアカウントにさいならする"
|
||||
currentVersion: "現在のバージョン"
|
||||
latestVersion: "最新のバージョン"
|
||||
youAreRunningUpToDateClient: "今使ってるクライアントが最新やで!"
|
||||
youAreRunningUpToDateClient: "今使こてるクライアントが最新やで!"
|
||||
newVersionOfClientAvailable: "新しいバージョンのクライアントが使えるで。"
|
||||
usageAmount: "使用量"
|
||||
capacity: "容量"
|
||||
|
@ -778,7 +778,7 @@ emailNotConfiguredWarning: "メアドの設定がされてへんで。"
|
|||
ratio: "比率"
|
||||
previewNoteText: "本文を下見するで"
|
||||
customCss: "カスタムCSS"
|
||||
customCssWarn: "この設定は必ず知識のある人がやらなあかんで。あんま良くない設定をしたるとクライアントがちゃんと使えへんくなってくで。"
|
||||
customCssWarn: "この設定は必ず知識のある人がやらなあかん。下手にいじるとわやなって使えんくなってまうで。"
|
||||
global: "グローバル"
|
||||
squareAvatars: "アイコンを四角形で表示するで"
|
||||
sent: "送信"
|
||||
|
@ -793,7 +793,7 @@ whatIsNew: "更新情報を見るで"
|
|||
translate: "翻訳"
|
||||
translatedFrom: "{x}から翻訳するで"
|
||||
accountDeletionInProgress: "アカウント削除しとるで待っとってなー"
|
||||
usernameInfo: "サーバー上であんたのアカウントをあんたやと分かるようにするための名前やで。アルファベット(a~z, A~Z)、数字(0~9)、それとアンダーバー(_)が使って考えてな。この名前は後から変更することはできへんからちゃんと考えるんやで。"
|
||||
usernameInfo: "サーバー上であんたのアカウントをあんたや分かるようにするための名前や。アルファベット(a~z, A~Z)、数字(0~9)、それとアンダーバー(_)が使えるで。この名前は後から変更することはでけへんから、ちゃんと考えや。"
|
||||
aiChanMode: "藍モードやで"
|
||||
keepCw: "CWを維持するで"
|
||||
pubSub: "Pub/Subのアカウント"
|
||||
|
@ -812,7 +812,7 @@ typeToConfirm: "この操作をやるんなら {x} と入力してなー"
|
|||
deleteAccount: "アカウント削除するで"
|
||||
document: "ドキュメント"
|
||||
numberOfPageCache: "ページキャッシュ数やで"
|
||||
numberOfPageCacheDescription: "増やすと使いやすくなる、負荷とメモリ使用量が増えてくで。一長一短やな。"
|
||||
numberOfPageCacheDescription: "増やすと使いやすくなるけど、サーバーの負荷とメモリ使用量が増えてまう。一長一短やな。"
|
||||
logoutConfirm: "ログアウトしまっか?"
|
||||
lastActiveDate: "最後に使った日時"
|
||||
statusbar: "ステータスバー"
|
||||
|
@ -1444,7 +1444,17 @@ _tutorial:
|
|||
step4_1: 投稿しとーみ
|
||||
step5_1: タイムライン! 文字と写真の宝石箱や~
|
||||
step5_2: うちのサーバーでは{timelines}種類のタイムラインをご用意しとります。
|
||||
step4_2: 最初は{introduction}に投稿したり、シンプルに「ここは賑やかどすなぁ。うちはそこまで喋れまへんが、どうぞよろしゅうに」などと投稿しはる方もいてます。
|
||||
step4_2: 最初は{introduction}に投稿したり、シンプルに「ここは賑やかどすなぁ」などと投稿しはる方もいてます。
|
||||
step5_7: グローバル{icon}タイムラインでは、接続しとるそこいらのサーバーからアレがガーッ流れてきてえらいこっちゃで。
|
||||
step5_6: おすすめ{icon}タイムラインでは、うちの管理人がばりおすすめしとるサーバーの投稿を表示させとうよ。
|
||||
step5_5: ソーシャル{icon}タイムラインでは、ホームタイムラインとローカルタイムラインの投稿が両方見られてホンマお得やわぁ。
|
||||
step5_3: ホーム{icon}タイムラインでは、あんたはんがフォローしてはる兄ちゃんらの投稿が見られまんねん。
|
||||
step5_4: ローカル{icon}タイムラインでは、このサーバーにおる人らの投稿を見られますわ。
|
||||
step6_1: ほんなら、ここはどないな場所なん?
|
||||
step6_2: 実は、あんたはんはFirefishに参加しただけやあらしまへん。ここは、何千もの相互接続されたサーバーが構成しとる Fediverse への入口どす。
|
||||
step6_3:
|
||||
それぞれのサーバーでは必ずしもFirefishが使われとるわけやなく、異なる動作をしはるサーバーもあります。せやけど、あんたはんは他のサーバーのアカウントもフォローしたり、返信・ブーストしたりできます。一見難儀そやけど、だんない!あんじょうやれますえ。
|
||||
step6_4: これで完了どす。楽しんどくれやす!
|
||||
_postForm:
|
||||
_placeholders:
|
||||
b: なんかおましたか?
|
||||
|
@ -1454,6 +1464,7 @@ _postForm:
|
|||
f: あんさん書くんを待っとるんどす...
|
||||
a: いまなにしとん?
|
||||
flagSpeakAsCat: 猫弁で喋る
|
||||
flagSpeakAsCatDescription: オンにすると、ワレの投稿の「な」を「にゃ」に変換したるで。
|
||||
flagSpeakAsCatDescription: オンにすると、ワレの投稿の「な」「na」を「にゃ」「nya」に変換したるで。
|
||||
welcomeBackWithName: おおきに、{name}はん
|
||||
migration: アカウントの引っ越し
|
||||
makeReactionsPublicDescription: あんたが付けたリアクションの一覧をみんなにも見せたるで。
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
_lang_: "Polski"
|
||||
headlineFirefish: "Otwartoźródłowa, zdecentralizowana sieć społecznościowa, która zawsze
|
||||
będzie darmowa! 🚀"
|
||||
headlineFirefish: "Otwartoźródłowa, zdecentralizowana sieć społecznościowa, która
|
||||
zawsze będzie darmowa! 🚀"
|
||||
introFirefish: "Hej! Firefish to otwartoźródłowa oraz zdecentralizowana sieć społecznościowa,
|
||||
która zawsze będzie darmowa! 🚀"
|
||||
monthAndDay: "{month}-{day}"
|
||||
|
@ -94,7 +94,7 @@ privacy: "Prywatność"
|
|||
makeFollowManuallyApprove: "Prośby o możliwość obserwacji wymagają zatwierdzenia"
|
||||
defaultNoteVisibility: "Domyślna widoczność"
|
||||
follow: "Obserwuj"
|
||||
followRequest: "Poproś o możliwość obserwacji"
|
||||
followRequest: "Poproś o możliwość obserwowania"
|
||||
followRequests: "Prośby o możliwość obserwacji"
|
||||
unfollow: "Przestań obserwować"
|
||||
followRequestPending: "Oczekująca prośba o możliwość obserwacji"
|
||||
|
@ -147,9 +147,9 @@ cacheRemoteFilesDescription: "Gdy ta opcja jest wyłączona, zdalne pliki są ł
|
|||
bezpośrednio ze zdalnego serwera. Wyłączenie tej opcji zmniejszy użycie powierzchni
|
||||
dyskowej, ale zwiększy transfer, ponieważ miniaturki nie będą generowane."
|
||||
flagAsBot: "To konto jest botem"
|
||||
flagAsBotDescription: "Jeżeli ten kanał jest kontrolowany przez jakiś program, ustaw
|
||||
tę opcję. Jeżeli włączona, będzie działać jako flaga informująca innych programistów,
|
||||
aby zapobiegać nieskończonej interakcji z różnymi botami i dostosowywać wewnętrzne
|
||||
flagAsBotDescription: "Ustaw tę opcję ten jeśli kanał kontrolowany jest przez jakiś
|
||||
program. Po włączeniu, będzie działać jako flaga informująca innych programistów,
|
||||
aby zapobiegać nieskończonej interakcji pomiędzy innymi botami i dostosowywać wewnętrzne
|
||||
systemy Firefish, traktując konto jako bota."
|
||||
flagAsCat: "Czy jesteś kotem? 😺"
|
||||
flagAsCatDescription: "Dostaniesz kocie uszka, oraz będziesz mówić jak kot!"
|
||||
|
@ -158,7 +158,7 @@ autoAcceptFollowed: "Automatycznie przyjmuj prośby o możliwość obserwacji od
|
|||
których obserwujesz"
|
||||
addAccount: "Dodaj konto"
|
||||
loginFailed: "Nie udało się zalogować"
|
||||
showOnRemote: "Zobacz na zdalnym serwerze"
|
||||
showOnRemote: "Zobacz oryginalną treść"
|
||||
general: "Ogólne"
|
||||
wallpaper: "Tapeta"
|
||||
setWallpaper: "Ustaw tapetę"
|
||||
|
@ -211,7 +211,7 @@ noUsers: "Brak użytkowników"
|
|||
editProfile: "Edytuj profil"
|
||||
noteDeleteConfirm: "Czy na pewno chcesz usunąć ten wpis?"
|
||||
pinLimitExceeded: "Nie możesz przypiąć więcej wpisów"
|
||||
intro: "Zakończono instalację Firefish! Utwórz konto administratora."
|
||||
intro: "Zakończono instalację Firefish! Utwórz teraz konto administratora."
|
||||
done: "Gotowe"
|
||||
processing: "Przetwarzanie"
|
||||
preview: "Podgląd"
|
||||
|
@ -299,11 +299,11 @@ emptyDrive: "Dysk jest pusty"
|
|||
emptyFolder: "Ten katalog jest pusty"
|
||||
unableToDelete: "Nie można usunąć"
|
||||
inputNewFileName: "Wprowadź nową nazwę pliku"
|
||||
inputNewDescription: "Proszę wpisać nowy napis"
|
||||
inputNewDescription: "Podaj nowy napis"
|
||||
inputNewFolderName: "Wprowadź nową nazwę katalogu"
|
||||
circularReferenceFolder: "Katalog docelowy jest podkatalogiem katalogu, który chcesz
|
||||
przenieść."
|
||||
hasChildFilesOrFolders: "Ponieważ ten katalog nie jest pusty, nie może być usunięty."
|
||||
hasChildFilesOrFolders: "Katalog nie może być usunięty ponieważ nie jest pusty."
|
||||
copyUrl: "Skopiuj adres URL"
|
||||
rename: "Zmień nazwę"
|
||||
avatar: "Awatar"
|
||||
|
@ -578,8 +578,8 @@ disablePlayer: "Zamknij odtwarzacz wideo"
|
|||
expandTweet: "Rozwiń tweet"
|
||||
themeEditor: "Edytor motywu"
|
||||
description: "Opis"
|
||||
describeFile: "Dodaj podpis"
|
||||
enterFileDescription: "Wprowadź napis"
|
||||
describeFile: "Dodaj opis"
|
||||
enterFileDescription: "Wprowadź opis"
|
||||
author: "Autor"
|
||||
leaveConfirm: "Są niezapisane zmiany. Czy chcesz je odrzucić?"
|
||||
manage: "Zarządzanie"
|
||||
|
@ -616,7 +616,7 @@ emptyToDisableSmtpAuth: "Pozostaw adres e-mail i hasło puste, aby wyłączyć w
|
|||
SMTP"
|
||||
smtpSecureInfo: "Wyłącz, jeżeli używasz STARTTLS"
|
||||
testEmail: "Przetestuj dostarczanie wiadomości e-mail"
|
||||
wordMute: "Wyciszenie słowa"
|
||||
wordMute: "Wyciszenie słów i języków"
|
||||
instanceMute: "Wyciszenie serwera"
|
||||
userSaysSomething: "{name} powiedział* coś"
|
||||
makeActive: "Aktywuj"
|
||||
|
@ -691,8 +691,7 @@ no: "Nie"
|
|||
driveFilesCount: "Liczba plików na dysku"
|
||||
driveUsage: "Użycie przestrzeni dyskowej"
|
||||
noCrawle: "Odrzuć indeksowanie przez crawlery"
|
||||
noCrawleDescription: "Proś wyszukiwarki internetowe, aby nie indeksowały Twojego profilu,
|
||||
wpisów, stron itd."
|
||||
noCrawleDescription: "Proś wyszukiwarki internetowe, aby nie indeksowały Twoich treści."
|
||||
lockedAccountInfo: "Dopóki nie ustawisz widoczności wpisu na \"Obserwujący\", twoje
|
||||
wpisy będą mogli widzieć wszyscy, nawet jeśli ustawisz manualne zatwierdzanie obserwujących."
|
||||
alwaysMarkSensitive: "Oznacz domyślnie jako NSFW"
|
||||
|
@ -759,7 +758,7 @@ useReactionPickerForContextMenu: "Otwórz wybornik reakcji prawym kliknięciem"
|
|||
typingUsers: "{users} pisze/ą"
|
||||
jumpToSpecifiedDate: "Przejdź do określonej daty"
|
||||
showingPastTimeline: "Obecnie wyświetla starą oś czasu"
|
||||
clear: "Wróć"
|
||||
clear: "Wyczyść"
|
||||
markAllAsRead: "Oznacz wszystkie jako przeczytane"
|
||||
goBack: "Wróć"
|
||||
unlikeConfirm: "Na pewno chcesz usunąć polubienie?"
|
||||
|
@ -800,7 +799,7 @@ gallery: "Galeria"
|
|||
recentPosts: "Ostatnie wpisy"
|
||||
popularPosts: "Popularne wpisy"
|
||||
shareWithNote: "Udostępnij z wpisem"
|
||||
ads: "Reklamy"
|
||||
ads: "Banery"
|
||||
expiration: "Ankieta kończy się"
|
||||
memo: "Notatki"
|
||||
priority: "Priorytet"
|
||||
|
@ -852,7 +851,7 @@ ffVisibility: "Widoczność obserwowanych/obserwujących"
|
|||
ffVisibilityDescription: "Pozwala skonfigurować, kto może zobaczyć, kogo obserwujesz
|
||||
i kto Cię obserwuje."
|
||||
continueThread: "Kontynuuj wątek"
|
||||
deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie Twojego konta. Kontynuować?"
|
||||
deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie tego konta. Kontynuować?"
|
||||
incorrectPassword: "Nieprawidłowe hasło."
|
||||
voteConfirm: "Potwierdzić swój głos na \"{choice}\"?"
|
||||
hide: "Ukryj"
|
||||
|
@ -1001,8 +1000,8 @@ _nsfw:
|
|||
force: "Ukrywaj wszystkie media"
|
||||
_mfm:
|
||||
cheatSheet: "Ściąga MFM"
|
||||
intro: "MFM jest językiem składniowym używanym przez m.in. Firefish, forki *key (w
|
||||
tym Firefish), oraz Akkomę, który może być użyty w wielu miejscach. Tu znajdziesz
|
||||
intro: "MFM jest językiem składniowym używanym przez m.in. Firefish, forki *key
|
||||
(w tym Firefish), oraz Akkomę, który może być użyty w wielu miejscach. Tu znajdziesz
|
||||
listę wszystkich możliwych elementów składni MFM."
|
||||
dummy: "Firefish rozszerza świat Fediwersum"
|
||||
mention: "Wspomnij"
|
||||
|
@ -1250,7 +1249,7 @@ _tutorial:
|
|||
innej połączonej instancji."
|
||||
step6_1: "Więc, czym to jest to miejsce?"
|
||||
step6_2: "Cóż, nie dołączył*ś po prostu do Firefish. Dołączył*ś do portalu do Fediverse,
|
||||
połączonej sieci tysięcy serwerów, zwanych instancjami."
|
||||
sieci tysięcy połączonych ze sobą serwerów, zwanych instancjami."
|
||||
step6_3: "Każdy serwer działa w inny sposób, i nie wszystkie serwery używają Firefish.
|
||||
Ten jednak używa! Jest to trochę skomplikowane, ale w krótkim czasie załapiesz
|
||||
o co chodzi."
|
||||
|
@ -1816,8 +1815,8 @@ instanceSecurity: Bezpieczeństwo serwera
|
|||
privateMode: Tryb prywatny
|
||||
allowedInstances: Dopuszczone serwery
|
||||
recommended: Polecane
|
||||
allowedInstancesDescription: Hosty serwerów, które mają być dopuszczone do federacji,
|
||||
każdy oddzielony nowym wierszem (dotyczy tylko trybu prywatnego).
|
||||
allowedInstancesDescription: Hosty serwerów, które mają być dopuszczone do federacji.
|
||||
Każdy oddzielony nowym wierszem (dotyczy tylko trybu prywatnego).
|
||||
seperateRenoteQuote: Oddziel przyciski podbicia i cytowania
|
||||
refreshInterval: 'Częstotliwość aktualizacji '
|
||||
slow: Wolna
|
||||
|
@ -1916,14 +1915,14 @@ sendErrorReportsDescription: "Gdy ta opcja jest włączona, szczegółowe inform
|
|||
błędach będą udostępnianie z Firefish gdy wystąpi problem, pomagając w ulepszaniu
|
||||
Firefish.\nZawrze to informacje takie jak wersja twojego systemu operacyjnego, przeglądarki,
|
||||
Twoja aktywność na Firefish itd."
|
||||
privateModeInfo: Gdy ta opcja jest włączona, tylko serwery z białej listy mogą federować
|
||||
się z twoim serwerem. Wszystkie posty będą ukryte publicznie.
|
||||
privateModeInfo: Gdy ta opcja jest włączona, tylko serwery z listy serwerów dozwolonych
|
||||
mogą federować się z twoim serwerem. Żadne posty nie będą publicznie dostępne.
|
||||
oneHour: Godzina
|
||||
oneDay: Dzień
|
||||
oneWeek: Tydzień
|
||||
recommendedInstances: Polecane serwery
|
||||
recommendedInstancesDescription: Polecane serwery, mające pojawić się w odpowiedniej
|
||||
osi czasu, oddzielane nowymi liniami. NIE dodawaj “https://”, TYLKO samą domenę.
|
||||
osi czasu, oddzielane nowymi liniami.
|
||||
rateLimitExceeded: Przekroczono ratelimit
|
||||
cropImage: Kadruj zdjęcie
|
||||
cropImageAsk: Czy chcesz skadrować to zdjęcie?
|
||||
|
@ -1948,7 +1947,7 @@ activeEmailValidationDescription: Włącza ściślejszą walidację adresów e-m
|
|||
obejmuje sprawdzanie adresów jednorazowych oraz tego, czy rzeczywiście można się
|
||||
z nim komunikować. Jeśli wyłączone, walidowany jest tylko format wiadomości e-mail.
|
||||
shuffle: Losuj
|
||||
showAds: Pokazuj reklamy
|
||||
showAds: Pokazuj banery
|
||||
enterSendsMessage: Wciśnij Enter w komunikatorze, by wysłać wiadomość (domyślnie –
|
||||
Ctrl + Enter)
|
||||
adminCustomCssWarn: To ustawienie powinno być używane tylko pod warunkiem, że wiesz
|
||||
|
@ -2012,7 +2011,7 @@ silencedInstancesDescription: Wypisz nazwy hostów serwerów, które chcesz wyci
|
|||
cannotUploadBecauseExceedsFileSizeLimit: Ten plik nie mógł być przesłany, ponieważ
|
||||
jego wielkość przekracza dozwolony limit.
|
||||
sendModMail: Wyślij Powiadomienie Moderacyjne
|
||||
searchPlaceholder: Szukaj Firefish
|
||||
searchPlaceholder: Szukaj w Firefish
|
||||
jumpToPrevious: Przejdź do poprzedniej sekcji
|
||||
listsDesc: Listy umożliwiają tworzenie osi czasu z określonymi użytkownikami. Dostęp
|
||||
do nich można uzyskać na stronie osi czasu.
|
||||
|
@ -2028,3 +2027,15 @@ newer: nowsze
|
|||
older: starsze
|
||||
cw: Ostrzeżenie zawartości
|
||||
removeReaction: Usuń reakcję
|
||||
reactions: Reakcje
|
||||
clipsDesc: Spinki to skategoryzowane zakładki, które można udostępniać. Możesz utworzyć
|
||||
spinkę dla każdego wpisu w menu wpisu.
|
||||
swipeOnMobile: Pozwalaj na przeciąganie pomiędzy stronami
|
||||
image: Obrazek
|
||||
xl: XL
|
||||
replies: Odpowiedzi
|
||||
video: Film
|
||||
quotes: Cytaty
|
||||
clickToShowPatterns: Kliknij aby pokazać wzory modułów
|
||||
renotes: Boosty
|
||||
audio: Dźwięk
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
_lang_: "Português"
|
||||
_lang_: "Português (Portugal)"
|
||||
headlineFirefish: "Uma rede ligada por notas"
|
||||
introFirefish: "Bem-vindo! Firefish é um serviço de microblogue descentralizado de
|
||||
código aberto, gratuito para sempre! 🚀"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
_lang_: Português (Brasil)
|
||||
username: Nome de usuário
|
||||
ok: OK
|
||||
_lang_: Inglês
|
||||
headlineFirefish: Uma plataforma de mídia social descentralizada e de código aberto
|
||||
que é gratuita para sempre! 🚀
|
||||
search: Pesquisar
|
||||
|
|
|
@ -111,7 +111,7 @@ you: "Вы"
|
|||
clickToShow: "Нажмите для просмотра"
|
||||
sensitive: "Содержимое не для всех"
|
||||
add: "Добавить"
|
||||
reaction: "Реакции"
|
||||
reaction: "Реакция"
|
||||
reactionSetting: "Реакции, отображаемые в палитре"
|
||||
reactionSettingDescription2: "Расставляйте перетаскиванием, удаляйте нажатием, добавляйте
|
||||
кнопкой «+»."
|
||||
|
@ -491,7 +491,7 @@ noFollowRequests: "Нерассмотренные запросы на подпи
|
|||
openImageInNewTab: "Открыть изображение в новой вкладке"
|
||||
dashboard: "Панель управления"
|
||||
local: "С этого сайта"
|
||||
remote: "С других сайтов"
|
||||
remote: "Исходный сайт"
|
||||
total: "Всего"
|
||||
weekOverWeekChanges: "За неделю"
|
||||
dayOverDayChanges: "За день"
|
||||
|
@ -2151,3 +2151,14 @@ deletePasskeysConfirm: Это действие безвозвратно удал
|
|||
на этом аккаунте. Продолжить?
|
||||
inputNotMatch: Введённые данные не совпадают
|
||||
addRe: Добавить "re:" в начале комментария в ответ на запись с предупреждением о содержимом
|
||||
detectPostLanguage: Автоматическое определение языка и отображение кнопки перевода
|
||||
для сообщений на иностранных языках
|
||||
indexableDescription: Разрешить встроенной поисковой системе искать ваши публичные
|
||||
записи
|
||||
reactions: Реакции
|
||||
indexable: Индексируемый(-ая)
|
||||
languageForTranslation: Язык перевода поста
|
||||
replies: Ответы
|
||||
quotes: Цитаты
|
||||
clickToShowPatterns: Нажмите, чтобы показать модуль шаблонов
|
||||
renotes: Репосты
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
_lang_: "ภาษาไทย"
|
||||
headlineFirefish: "เชื่อมต่อเครือข่ายโดยโน้ต"
|
||||
introFirefish: "ยินดีต้อนรับค่ะ/ครับ! Firefish เป็นแพลตฟอร์มโซเชียลมีเดียแบบโอเพ่นซอร์สที่มีการกระจายอำนาจซึ่งให้บริการฟรีตลอดไป!
|
||||
headlineFirefish: "แพลตฟอร์มโซเชียลมีเดียแบบโอเพนซอร์สที่มีการกระจายอำนาจซึ่งให้บริการฟรีตลอดไป!
|
||||
🚀"
|
||||
introFirefish: "ยินดีต้อนรับค่ะ/ครับ! Firefish เป็นแพลตฟอร์มโซเชียลมีเดียแบบโอเพนซอร์สที่มีการกระจายอำนาจซึ่งให้บริการฟรีตลอดไป!
|
||||
🚀"
|
||||
monthAndDay: "{เดือน}/{วัน}"
|
||||
search: "ค้นหา"
|
||||
notifications: "การเเจ้งเตือน"
|
||||
username: "ชื่อผู้ใช้"
|
||||
password: "รหัสผ่าน"
|
||||
forgotPassword: "ลืมรหัสผ่านอ่ะ"
|
||||
fetchingAsApObject: "กำลังดึงข้อมูล จาก เฟดิเวิร์ส"
|
||||
forgotPassword: "ลืมรหัสผ่าน"
|
||||
fetchingAsApObject: "กำลังดึงข้อมูลจากเฟดิเวิร์ส"
|
||||
ok: "ตกลง"
|
||||
gotIt: "เข้าใจแล้ว !"
|
||||
cancel: "ยกเลิก"
|
||||
enterUsername: "ใส่ชื่อผู้ใช้"
|
||||
renotedBy: "บูตเตอร์โดย {user}"
|
||||
renotedBy: "บูสต์โดย {user}"
|
||||
noNotes: "ไม่มีโพสต์"
|
||||
noNotifications: "ไม่มีการแจ้งเตือน"
|
||||
instance: "เซิฟเวอร์"
|
||||
instance: "เซิร์ฟเวอร์"
|
||||
settings: "การตั้งค่า"
|
||||
basicSettings: "การตั้งค่าพื้นฐาน"
|
||||
otherSettings: "การตั้งค่าอื่นๆ"
|
||||
otherSettings: "การตั้งค่าอื่น ๆ"
|
||||
openInWindow: "เปิดในหน้าต่าง"
|
||||
profile: "โปรไฟล์"
|
||||
timeline: "ไทม์ไลน์"
|
||||
|
@ -28,14 +29,14 @@ login: "เข้าสู่ระบบ"
|
|||
loggingIn: "กำลังเข้าสู่ระบบ"
|
||||
logout: "ออกจากระบบ"
|
||||
signup: "สร้างบัญชีผู้ใช้"
|
||||
uploading: "กำลังอัพโหลด..."
|
||||
uploading: "กำลังอัปโหลด..."
|
||||
save: "บันทึก"
|
||||
users: "ผู้ใช้งาน"
|
||||
addUser: "เพิ่มผู้ใช้"
|
||||
favorite: "รายการโปรด"
|
||||
favorite: "เพิ่มลงในรายการโปรด"
|
||||
favorites: "รายการโปรด"
|
||||
unfavorite: "ลบออกจากรายการโปรด"
|
||||
favorited: "เพิ่มแล้วในรายการโปรด"
|
||||
favorited: "เพิ่มในรายการโปรดแล้ว"
|
||||
alreadyFavorited: "เพิ่มในรายการโปรดอยู่แล้ว"
|
||||
cantFavorite: "ไม่สามารถเพิ่มในรายการโปรดได้"
|
||||
pin: "ปักหมุดไปยังโปรไฟล์"
|
||||
|
@ -55,22 +56,22 @@ loadMore: "โหลดเพิ่มเติม"
|
|||
showMore: "แสดงเพิ่มเติม"
|
||||
showLess: "ปิด"
|
||||
youGotNewFollower: "ได้ติดตามคุณ"
|
||||
receiveFollowRequest: "คำขอผู้ติดตามที่ได้รับ"
|
||||
followRequestAccepted: "ผู้ติดตามได้ตอบรับคำขอร้องของคุณแล้ว"
|
||||
receiveFollowRequest: "ได้รับคำขอติดตาม"
|
||||
followRequestAccepted: "ผู้ติดตามได้ตอบรับคำขอของคุณแล้ว"
|
||||
mention: "กล่าวถึง"
|
||||
mentions: "พูดถึง"
|
||||
mentions: "กล่าวถึง"
|
||||
directNotes: "ไดเร็คข้อความ"
|
||||
importAndExport: "นำเข้า / ส่งออก"
|
||||
import: "การนำเข้า"
|
||||
export: "การนำออก"
|
||||
importAndExport: "นำเข้า / ส่งออกข้อมูล"
|
||||
import: "นำเข้า"
|
||||
export: "ส่งออก"
|
||||
files: "ไฟล์"
|
||||
download: "ดาวน์โหลด"
|
||||
driveFileDeleteConfirm: "คุณแน่ใจแล้วหรอว่าต้องการลบไฟล์ \"{name}\"? โพสต์ย่อที่แนบมากับไฟล์นี้ก็จะถูกลบด้วยนะ"
|
||||
unfollowConfirm: "คุณแน่ใจแล้วหรอว่าต้องการเลิกติดตาม {name}?"
|
||||
exportRequested: "เมื่อคุณได้ร้องขอการส่งออก อาจจะต้องใช้เวลาสักครู่ และจะถูกเพิ่มในไดรฟ์ของคุณเมื่อเสร็จสิ้นแล้ว"
|
||||
importRequested: "เมื่อคุณได้ร้องขอการนำเข้า อาจจะต้องใช้เวลาสักครู่นะ"
|
||||
lists: "รายการ"
|
||||
noLists: "คุณไม่มีลิสต์ใดๆนะ"
|
||||
importRequested: "คุณได้ร้องขอการนำเข้า อาจจะต้องใช้เวลาสักครู่นะ"
|
||||
lists: "ลิสต์"
|
||||
noLists: "คุณไม่มีลิสต์ใด ๆ"
|
||||
note: "โพสต์"
|
||||
notes: "โพสต์"
|
||||
following: "กำลังติดตาม"
|
||||
|
@ -79,76 +80,76 @@ followsYou: "ติดตามคุณ"
|
|||
createList: "สร้างลิสต์"
|
||||
manageLists: "จัดการลิสต์"
|
||||
error: "ผิดพลาด"
|
||||
somethingHappened: "อุ๊ย ! มีอะไรบางอย่างผิดพลาด"
|
||||
somethingHappened: "เกิดข้อผิดพลาด"
|
||||
retry: "ลองใหม่อีกครั้ง"
|
||||
pageLoadError: "เกิดข้อผิดพลาดในการโหลดหน้านี้"
|
||||
pageLoadErrorDescription: "โดยปกติแล้วมักจะเกิดจากข้อผิดพลาดของเครือข่ายหรือแคชของเบราว์เซอร์
|
||||
ลองล้างแคชแล้วลองใหม่อีกครั้งหลังจากรอสักครู่นะ"
|
||||
serverIsDead: "เซิร์ฟเวอร์นี้ไม่มีการตอบสนอง ได้โปรดกรุณารอสักครู่แล้วลองใหม่อีกครั้งนะ"
|
||||
youShouldUpgradeClient: "หากต้องการดูหน้านี้ได้โปรดกรุณา รีเซ็ตเพื่ออัปเดตไคลเอ็นต์ของคุณนะ"
|
||||
enterListName: "ใส่ชื่อสำหรับรายการลิสต์"
|
||||
serverIsDead: "เซิร์ฟเวอร์นี้ไม่มีการตอบสนอง กรุณารอสักครู่แล้วลองใหม่อีกครั้งนะ"
|
||||
youShouldUpgradeClient: "หากต้องการดูหน้านี้ กรุณารีเฟรชเพื่ออัปเดตไคลเอ็นต์ของคุณ"
|
||||
enterListName: "ใส่ชื่อสำหรับลิสต์"
|
||||
privacy: "ความเป็นส่วนตัว"
|
||||
makeFollowManuallyApprove: "ติดตามคำขอที่ต้องได้รับการอนุมัติ"
|
||||
makeFollowManuallyApprove: "คำขอติดตามต้องได้รับการอนุมัติ"
|
||||
defaultNoteVisibility: "การมองเห็นที่เป็นค่าเริ่มต้น"
|
||||
follow: "กำลังติดตาม"
|
||||
follow: "ติดตาม"
|
||||
followRequest: "คำขอติดตาม"
|
||||
followRequests: "ติดตามการร้องขอ"
|
||||
followRequests: "การติดตามที่ร้องขอ"
|
||||
unfollow: "เลิกติดตาม"
|
||||
followRequestPending: "กำลังรอดำเนินการร้องขอติดตาม"
|
||||
enterEmoji: "ใส่อีโมจิ"
|
||||
renote: "บูสต์"
|
||||
unrenote: "เลิกบูสต์"
|
||||
renoted: "บูสต์แล้ว"
|
||||
cantRenote: "โพสต์นี้ไม่สามารถบูสต์ใหม่ได้"
|
||||
cantReRenote: "ไม่สามารถบูสต์ไว้ใหม่ได้"
|
||||
quote: "อ้างคำพูด"
|
||||
cantRenote: "โพสต์นี้ไม่สามารถบูสต์ได้"
|
||||
cantReRenote: "ไม่สามารถบูสต์การบูสต์ได้"
|
||||
quote: "โควต"
|
||||
pinnedNote: "โพสต์ที่ปักหมุดแล้ว"
|
||||
pinned: "ปักหมุดไปยังโปรไฟล์"
|
||||
you: "ตัวเอง"
|
||||
you: "คุณ"
|
||||
clickToShow: "คลิกเพื่อแสดง"
|
||||
sensitive: "เนื้อหาที่ละเอียดอ่อน NSFW"
|
||||
sensitive: "เนื้อหาที่ละเอียดอ่อน"
|
||||
add: "เพิ่ม"
|
||||
reaction: "รีแอคชั่น"
|
||||
reactionSetting: "รีแอคชั่นไปยังแสดงผลในตัวเลือกการรีแอคชั่น"
|
||||
reactionSettingDescription2: "กดลากเพื่อจัดลำดับใหม่ กดคลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม"
|
||||
reaction: "รีแอคชัน"
|
||||
reactionSetting: "รีแอคชันที่จะแสดงผลในตัวเลือกการรีแอคชัน"
|
||||
reactionSettingDescription2: "ลากเพื่อจัดลำดับใหม่ คลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม"
|
||||
rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นโพสต์"
|
||||
attachCancel: "ลบไฟล์ออกที่แนบมา"
|
||||
attachCancel: "ลบไฟล์ที่แนบมา"
|
||||
markAsSensitive: "ทำเครื่องหมายว่าละเอียดอ่อน"
|
||||
unmarkAsSensitive: "ยกเลิกทำเครื่องหมายเป็น NSFW"
|
||||
unmarkAsSensitive: "ยกเลิกทำเครื่องหมายว่าละเอียดอ่อน"
|
||||
enterFileName: "พิมพ์ชื่อไฟล์"
|
||||
mute: "ปิดเสียง"
|
||||
unmute: "ไม่ปิดเสียง"
|
||||
unmute: "ยกเลิกการปิดเสียง"
|
||||
block: "บล็อค"
|
||||
unblock: "เลิกปิดกั้น"
|
||||
unblock: "เลิกบล็อค"
|
||||
suspend: "ถูกระงับ"
|
||||
unsuspend: "ยกเลิกระงับ"
|
||||
blockConfirm: "คุณแน่ใจแล้วเหรอ ว่าต้องการบล็อกบัญชีนี้?"
|
||||
blockConfirm: "คุณแน่ใจแล้วเหรอ ว่าต้องการบล็อคบัญชีนี้?"
|
||||
unblockConfirm: "คุณแน่ใจแล้วเหรอ ว่าต้องการปลดบล็อคบัญชีนี้?"
|
||||
suspendConfirm: "คุณแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้อ่ะ?"
|
||||
suspendConfirm: "คุณแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้?"
|
||||
unsuspendConfirm: "คุณแน่ใจแล้วหรอว่าต้องการยกเลิกการระงับบัญชีนี้?"
|
||||
selectList: "เลือกรายการ"
|
||||
selectList: "เลือกลิสต์"
|
||||
selectAntenna: "เลือกเสาอากาศ"
|
||||
selectWidget: "เลือกวิดเจ็ต"
|
||||
editWidgets: "แก้ไขวิดเจ็ต"
|
||||
editWidgetsExit: "เรียบร้อย"
|
||||
customEmojis: "กำหนดอีโมจิเอง"
|
||||
customEmojis: "อีโมจิที่กำหนดเอง"
|
||||
emoji: "อีโมจิ"
|
||||
emojis: "อีโมจิ"
|
||||
emojiName: "ชื่ออิโมจิ"
|
||||
emojiUrl: "อิโมจิ URL"
|
||||
addEmoji: "แทรกอีโมจิ"
|
||||
emojiUrl: "URL ของอิโมจิ"
|
||||
addEmoji: "เพิ่มอีโมจิ"
|
||||
settingGuide: "การตั้งค่าที่แนะนำ"
|
||||
cacheRemoteFiles: "แคชไฟล์ระยะไกล"
|
||||
cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากระยะไกลเซิฟเวอร์
|
||||
แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน
|
||||
cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดจากเซิร์ฟเวอร์ระยะไกลโดยตรง
|
||||
แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณทราฟฟิค
|
||||
เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ"
|
||||
flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท"
|
||||
flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม
|
||||
หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ
|
||||
และยังสามารถปรับเปลี่ยนระบบภายในของ Firefish เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท"
|
||||
flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบัญชีอัตโนมัติ"
|
||||
flagAsBotDescription: "เปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยโปรแกรม หากเปิดใช้งาน
|
||||
มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่น ๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบัญชีอัตโนมัติอื่นๆ
|
||||
และปรับเปลี่ยนระบบภายในของ Firefish เพื่อปฏิบัติต่อบัญชีนี้เป็นบัญชีอัตโนมัติ"
|
||||
flagAsCat: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
|
||||
flagAsCatDescription: "คุณจะได้รับหูแมวและพูดเหมือนแมวนะ!"
|
||||
flagShowTimelineReplies: "แสดงตอบกลับ ในไทม์ไลน์"
|
||||
flagShowTimelineReplies: "แสดงการตอบกลับ ในไทม์ไลน์"
|
||||
flagShowTimelineRepliesDescription: "แสดงการตอบกลับของผู้ใช้งานไปยังโพสต์ของผู้ใช้งานรายอื่นๆในไทม์ไลน์หากได้เปิดเอาไว้"
|
||||
autoAcceptFollowed: "อนุมัติคำขอติดตามโดยอัตโนมัติทันที จากผู้ใช้งานที่คุณกำลังติดตาม"
|
||||
addAccount: "เพิ่มบัญชี"
|
||||
|
@ -1245,22 +1246,28 @@ _deck:
|
|||
list: "รายการ"
|
||||
mentions: "พูดถึง"
|
||||
noThankYou: ไม่ล่ะขอบคุณ
|
||||
removeReaction: ลบรีเเอดชั่นของคุณ
|
||||
renoteMute: ปิดเสียงบูส
|
||||
renoteUnmute: เลิกปิดเสียงบูส
|
||||
removeReaction: ลบรีเเอคชันของคุณ
|
||||
renoteMute: ปิดเสียงบูสต์
|
||||
renoteUnmute: เลิกปิดเสียงบูสต์
|
||||
manageGroups: จัดการกลุ่ม
|
||||
addInstance: เพิ่มเซิฟเวอร์
|
||||
searchPlaceholder: ค้นหา Firefish
|
||||
addInstance: เพิ่มเซิร์ฟเวอร์
|
||||
searchPlaceholder: ค้นหาใน Firefish
|
||||
deleted: ลบแล้ว
|
||||
editNote: แก้ไขโพสต์
|
||||
edited: แก้ไขแล้วเมื่อ {date} {time}
|
||||
jumpToPrevious: ข้ามไปที่ก่อนหน้านี้
|
||||
listsDesc: ลิสต์รายการนั้นช่วยให้คุณได้สร้างไทม์ไลน์กับผู้ใช้ที่ระบุได้นะ ยังสามารถเข้าถึงได้จากหน้าไทม์ไลน์ได้อีกด้วย
|
||||
enableEmojiReactions: เปิดใช้งานรีแอดชั่นอีโมจิ
|
||||
listsDesc: ลิสต์นั้นช่วยให้คุณได้สร้างไทม์ไลน์กับผู้ใช้ที่ระบุได้ คุณสามารถเข้าถึงได้จากหน้าไทม์ไลน์
|
||||
enableEmojiReactions: เปิดใช้งานรีแอคชันอีโมจิ
|
||||
selectChannel: เลือกช่อง
|
||||
older: เก่ากว่านี้
|
||||
newer: ใหม่กว่านี้
|
||||
older: เก่ากว่า
|
||||
newer: ใหม่กว่า
|
||||
selectInstance: เลือกเซิฟเวอร์
|
||||
showEmojisInReactionNotifications: แสดงอิโมจิในการแจ้งเตือนรีแอคชั่น
|
||||
showEmojisInReactionNotifications: แสดงอิโมจิในการแจ้งเตือนรีแอคชัน
|
||||
flagSpeakAsCat: พูดเหมือนแมว
|
||||
cw: คำเตือนเนื้อหา
|
||||
reactions: รีแอคชัน
|
||||
replies: การตอบกลับ
|
||||
quotes: โควต
|
||||
clickToShowPatterns: คลิกเพื่อแสดงรูปแบบโมดูล
|
||||
renotes: บูสต์
|
||||
flagSpeakAsCatDescription: ในโหมดแมว โพสต์ของคุณจะถูกทำให้เป็นแมว
|
||||
|
|
|
@ -900,8 +900,8 @@ customKaTeXMacro: "自訂KaTeX巨集"
|
|||
customKaTeXMacroDescription: "使用巨集來輕鬆輸入數學表達式吧!巨集的用法與 LaTeX 中的命令定義相同。你可以使用 \\newcommand{\\
|
||||
name}{content} 或 \\newcommand{\\name}[number of arguments]{content} 來輸入數學表達式。舉例來說,\\
|
||||
newcommand{\\add}[2]{#1 + #2} 會將 \\add{3}{foo} 展開為 3 + foo。巨集名稱除了可用大括號 {} 括起來之外,也可使用小括號
|
||||
() 和中括號 [],但使用於巨集參數的括號會有所變更。每行只能夠定義一個巨集,巨集中間無法間換。無效的行將被忽略。只支援簡單字串的替換功能,不支援條件分歧的進階語法。"
|
||||
enableCustomKaTeXMacro: "啟用自定義 KaTeX 宏"
|
||||
() 和中括號 [],但使用於巨集參數的括號會有所變更。每行只能定義一個巨集,巨集中間無法換行,無效的行將被忽略。只支援簡單字串的替換功能,不支援條件分歧的進階語法。"
|
||||
enableCustomKaTeXMacro: "啟用自訂 KaTeX 巨集"
|
||||
_sensitiveMediaDetection:
|
||||
description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。"
|
||||
sensitivity: "檢測敏感度"
|
||||
|
@ -1994,3 +1994,12 @@ indexable: 登錄至貼文搜尋引擎
|
|||
origin: 來源
|
||||
objectStorageS3ForcePathStyle: 使用基於路徑的端點(Endpoint)URL
|
||||
clickToShowPatterns: 點擊顯示模組模式(Module Pattern)
|
||||
iconSet: 圖示的樣式
|
||||
_iconSets:
|
||||
fill: 填滿
|
||||
regular: 標準
|
||||
bold: 粗線
|
||||
duotone: 雙色
|
||||
light: 細線
|
||||
showAttachedNotes: 顯示有此附件的貼文
|
||||
attachedToNotes: 帶有此附件的貼文
|
||||
|
|
42
package.json
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "firefish",
|
||||
"version": "1.0.5-dev18",
|
||||
"version": "1.0.5-rc",
|
||||
"codename": "aqua",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.joinfirefish.org/firefish/firefish.git"
|
||||
},
|
||||
"packageManager": "pnpm@8.8.0",
|
||||
"packageManager": "pnpm@8.11.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"rebuild": "pnpm run clean && pnpm run build",
|
||||
|
@ -19,7 +19,7 @@
|
|||
"migrateandstart": "pnpm run migrate && pnpm run start",
|
||||
"gulp": "gulp build",
|
||||
"watch": "pnpm run dev",
|
||||
"dev": "pnpm node ./scripts/dev.js",
|
||||
"dev": "pnpm node ./scripts/dev.mjs",
|
||||
"dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start",
|
||||
"lint": "pnpm -r --parallel run lint",
|
||||
"debug": "pnpm run build:debug && pnpm run start",
|
||||
|
@ -30,42 +30,42 @@
|
|||
"mocha": "pnpm --filter backend run mocha",
|
||||
"test": "pnpm run mocha",
|
||||
"format": "pnpm -r --parallel run format",
|
||||
"clean": "pnpm node ./scripts/clean.js",
|
||||
"clean-all": "pnpm node ./scripts/clean-all.js",
|
||||
"clean": "pnpm node ./scripts/clean.mjs",
|
||||
"clean-all": "pnpm node ./scripts/clean-all.mjs",
|
||||
"cleanall": "pnpm run clean-all"
|
||||
},
|
||||
"resolutions": {
|
||||
"chokidar": "^3.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bull-board/api": "5.8.0",
|
||||
"@bull-board/ui": "5.8.0",
|
||||
"@napi-rs/cli": "^2.16.2",
|
||||
"@tensorflow/tfjs": "^4.10.0",
|
||||
"@bull-board/api": "5.9.1",
|
||||
"@bull-board/ui": "5.9.1",
|
||||
"@napi-rs/cli": "^2.16.5",
|
||||
"@tensorflow/tfjs": "^4.13.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"seedrandom": "^3.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.0.0",
|
||||
"@biomejs/cli-darwin-arm64": "^1.0.0",
|
||||
"@biomejs/cli-darwin-x64": "^1.0.0",
|
||||
"@biomejs/cli-linux-arm64": "^1.0.0",
|
||||
"@biomejs/cli-linux-x64": "^1.0.0",
|
||||
"@types/gulp": "4.0.13",
|
||||
"@types/gulp-rename": "2.0.2",
|
||||
"@types/node": "20.5.8",
|
||||
"@biomejs/biome": "1.3.3",
|
||||
"@biomejs/cli-darwin-arm64": "^1.3.3",
|
||||
"@biomejs/cli-darwin-x64": "^1.3.3",
|
||||
"@biomejs/cli-linux-arm64": "^1.3.3",
|
||||
"@biomejs/cli-linux-x64": "^1.3.3",
|
||||
"@types/gulp": "4.0.17",
|
||||
"@types/gulp-rename": "2.0.5",
|
||||
"@types/node": "20.9.0",
|
||||
"add": "2.0.6",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "10.11.0",
|
||||
"execa": "5.1.1",
|
||||
"cypress": "13.5.1",
|
||||
"execa": "8.0.1",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-cssnano": "2.1.3",
|
||||
"gulp-rename": "2.0.0",
|
||||
"gulp-replace": "1.1.4",
|
||||
"gulp-terser": "2.1.0",
|
||||
"install-peers": "^1.0.4",
|
||||
"pnpm": "8.8.0",
|
||||
"start-server-and-test": "1.15.2",
|
||||
"pnpm": "8.11.0",
|
||||
"start-server-and-test": "2.0.3",
|
||||
"typescript": "5.2.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,3 +7,4 @@ This directory contains all of the packages Firefish uses.
|
|||
- `client`: Web interface written in Vue3 and TypeScript
|
||||
- `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript
|
||||
- `firefish-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/firefish-js) for public use
|
||||
- `megalodon`: TypeScript library used for partial Mastodon API compatibility
|
||||
|
|
BIN
packages/backend/assets/notification-badges/boost.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 889 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
packages/backend/assets/notification-badges/reaction.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 798 B |
13
packages/backend/migration/1699305365258-more-urls.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export class MoreUrls1699305365258 {
|
||||
name = "MoreUrls1699305365258";
|
||||
|
||||
async up(queryRunner) {
|
||||
queryRunner.query(
|
||||
`ALTER TABLE "meta" ADD "moreUrls" jsonb NOT NULL DEFAULT '[]'`,
|
||||
);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "moreUrls"`);
|
||||
}
|
||||
}
|
|
@ -75,6 +75,8 @@ pub struct Model {
|
|||
pub pinned_users: StringVec,
|
||||
#[sea_orm(column_name = "ToSUrl")]
|
||||
pub to_s_url: Option<String>,
|
||||
#[sea_orm(column_name = "moreUrls", column_type = "JsonBinary")]
|
||||
pub more_urls: Json,
|
||||
#[sea_orm(column_name = "repositoryUrl")]
|
||||
pub repository_url: String,
|
||||
#[sea_orm(column_name = "feedbackUrl")]
|
||||
|
|
|
@ -23,36 +23,36 @@
|
|||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-android-arm64": "1.3.11",
|
||||
"@tensorflow/tfjs-node": "3.21.1"
|
||||
"@tensorflow/tfjs-node": "4.13.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bull-board/api": "5.8.0",
|
||||
"@bull-board/koa": "5.8.0",
|
||||
"@bull-board/ui": "5.8.0",
|
||||
"@discordapp/twemoji": "14.1.2",
|
||||
"@elastic/elasticsearch": "7.17.0",
|
||||
"@koa/cors": "3.4.3",
|
||||
"@bull-board/api": "5.9.1",
|
||||
"@bull-board/koa": "5.9.1",
|
||||
"@bull-board/ui": "5.9.1",
|
||||
"@discordapp/twemoji": "^15.0.2",
|
||||
"@elastic/elasticsearch": "8.10.0",
|
||||
"@koa/cors": "4.0.0",
|
||||
"@koa/multer": "3.0.2",
|
||||
"@koa/router": "9.0.1",
|
||||
"@koa/router": "12.0.1",
|
||||
"@ladjs/koa-views": "9.0.0",
|
||||
"@peertube/http-signature": "1.7.0",
|
||||
"@redocly/openapi-core": "1.0.2",
|
||||
"@sinonjs/fake-timers": "9.1.2",
|
||||
"@syuilo/aiscript": "0.11.1",
|
||||
"@tensorflow/tfjs": "^4.2.0",
|
||||
"@redocly/openapi-core": "1.4.1",
|
||||
"@sinonjs/fake-timers": "11.2.2",
|
||||
"@tensorflow/tfjs": "^4.13.0",
|
||||
"@twemoji/parser": "^15.0.0",
|
||||
"adm-zip": "^0.5.10",
|
||||
"ajv": "8.12.0",
|
||||
"archiver": "6.0.0",
|
||||
"argon2": "^0.31.1",
|
||||
"autolinker": "4.0.0",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.1413.0",
|
||||
"axios": "^1.4.0",
|
||||
"archiver": "6.0.1",
|
||||
"argon2": "^0.31.2",
|
||||
"aws-sdk": "2.1498.0",
|
||||
"axios": "^1.6.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "2.0.5",
|
||||
"bull": "4.11.3",
|
||||
"bull": "4.11.5",
|
||||
"cacheable-lookup": "TheEssem/cacheable-lookup",
|
||||
"cbor-x": "^1.5.4",
|
||||
"chalk": "5.3.0",
|
||||
"chalk-template": "0.4.0",
|
||||
"chalk-template": "1.1.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"cli-highlight": "2.1.11",
|
||||
"color-convert": "2.0.1",
|
||||
|
@ -62,19 +62,18 @@
|
|||
"deep-email-validator": "0.1.21",
|
||||
"escape-regexp": "0.0.1",
|
||||
"feed": "4.2.2",
|
||||
"file-type": "18.5.0",
|
||||
"firefish-js": "workspace:*",
|
||||
"file-type": "18.7.0",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"got": "13.0.0",
|
||||
"gunzip-maybe": "^1.4.2",
|
||||
"happy-dom": "^11.0.2",
|
||||
"happy-dom": "^12.10.3",
|
||||
"hpagent": "1.2.0",
|
||||
"ioredis": "5.3.2",
|
||||
"ip-cidr": "3.1.0",
|
||||
"is-svg": "5.0.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"json5": "2.2.3",
|
||||
"jsonld": "8.2.1",
|
||||
"jsonld": "8.3.1",
|
||||
"jsrsasign": "10.8.6",
|
||||
"koa": "2.14.2",
|
||||
"koa-body": "^6.0.1",
|
||||
|
@ -86,117 +85,117 @@
|
|||
"koa-remove-trailing-slashes": "2.0.3",
|
||||
"koa-send": "5.0.1",
|
||||
"koa-slow": "2.1.0",
|
||||
"koa-views": "7.0.2",
|
||||
"megalodon": "8.1.1",
|
||||
"meilisearch": "0.34.1",
|
||||
"megalodon": "workspace:*",
|
||||
"meilisearch": "0.35.0",
|
||||
"mfm-js": "0.23.3",
|
||||
"mime-types": "2.1.35",
|
||||
"msgpackr": "1.9.7",
|
||||
"multer": "1.4.4-lts.1",
|
||||
"msgpackr": "^1.9.9",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"native-utils": "link:native-utils",
|
||||
"nested-property": "4.0.0",
|
||||
"node-fetch": "3.3.2",
|
||||
"nodemailer": "6.9.4",
|
||||
"nodemailer": "6.9.7",
|
||||
"nsfwjs": "2.4.2",
|
||||
"opencc-js": "^1.0.5",
|
||||
"os-utils": "0.0.14",
|
||||
"otpauth": "^9.1.4",
|
||||
"otpauth": "^9.2.0",
|
||||
"parse5": "7.1.2",
|
||||
"pg": "8.11.3",
|
||||
"private-ip": "3.0.1",
|
||||
"probe-image-size": "7.2.3",
|
||||
"promise-limit": "2.7.0",
|
||||
"punycode": "2.3.0",
|
||||
"pureimage": "0.4.8",
|
||||
"punycode": "2.3.1",
|
||||
"pureimage": "0.4.13",
|
||||
"qrcode": "1.5.3",
|
||||
"qs": "6.11.2",
|
||||
"random-seed": "0.3.0",
|
||||
"ratelimiter": "3.4.1",
|
||||
"re2": "1.20.3",
|
||||
"re2": "1.20.8",
|
||||
"redis-semaphore": "5.5.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rename": "1.0.4",
|
||||
"rndstr": "1.0.0",
|
||||
"rss-parser": "3.13.0",
|
||||
"sanitize-html": "2.11.0",
|
||||
"seedrandom": "^3.0.5",
|
||||
"semver": "7.5.4",
|
||||
"sharp": "0.32.5",
|
||||
"sharp": "0.32.6",
|
||||
"sonic-channel": "^1.3.1",
|
||||
"stringz": "2.1.0",
|
||||
"summaly": "2.7.0",
|
||||
"syslog-pro": "1.0.0",
|
||||
"systeminformation": "5.21.3",
|
||||
"systeminformation": "5.21.17",
|
||||
"tar-stream": "^3.1.6",
|
||||
"tesseract.js": "^4.1.1",
|
||||
"tesseract.js": "^5.0.3",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tinyld": "^1.3.4",
|
||||
"tmp": "0.2.1",
|
||||
"twemoji-parser": "14.0.0",
|
||||
"typeorm": "0.3.17",
|
||||
"ulid": "2.3.0",
|
||||
"uuid": "9.0.0",
|
||||
"web-push": "3.6.5",
|
||||
"uuid": "9.0.1",
|
||||
"web-push": "3.6.6",
|
||||
"websocket": "1.0.34",
|
||||
"xev": "3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/cli": "^0.1.62",
|
||||
"@swc/cli": "^0.1.63",
|
||||
"@swc/core": "1.3.78",
|
||||
"@types/adm-zip": "^0.5.0",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/escape-regexp": "0.0.1",
|
||||
"@types/fluent-ffmpeg": "2.1.21",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
"@types/jsonld": "1.5.9",
|
||||
"@types/jsrsasign": "10.5.8",
|
||||
"@types/koa": "2.13.8",
|
||||
"@types/koa-bodyparser": "4.3.10",
|
||||
"@types/koa-cors": "0.0.2",
|
||||
"@types/koa-favicon": "2.0.21",
|
||||
"@types/koa-logger": "3.1.2",
|
||||
"@types/koa-mount": "4.0.2",
|
||||
"@types/koa-send": "4.1.3",
|
||||
"@types/koa-views": "7.0.0",
|
||||
"@types/koa__cors": "3.3.0",
|
||||
"@types/koa__multer": "2.0.4",
|
||||
"@types/koa__router": "8.0.11",
|
||||
"@types/mocha": "9.1.1",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/node-fetch": "3.0.3",
|
||||
"@types/nodemailer": "6.4.9",
|
||||
"@types/oauth": "0.9.1",
|
||||
"@types/probe-image-size": "^7.2.0",
|
||||
"@types/pug": "2.0.6",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/qrcode": "1.5.1",
|
||||
"@types/qs": "6.9.7",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/ratelimiter": "3.4.4",
|
||||
"@types/redis": "4.0.11",
|
||||
"@types/rename": "1.0.4",
|
||||
"@types/sanitize-html": "2.9.0",
|
||||
"@types/semver": "7.5.0",
|
||||
"@types/sinonjs__fake-timers": "8.1.2",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@types/tmp": "0.2.3",
|
||||
"@types/uuid": "9.0.2",
|
||||
"@types/web-push": "3.3.2",
|
||||
"@types/websocket": "1.0.5",
|
||||
"@types/ws": "8.5.5",
|
||||
"@types/adm-zip": "^0.5.4",
|
||||
"@types/bcryptjs": "2.4.6",
|
||||
"@types/color-convert": "^2.0.3",
|
||||
"@types/content-disposition": "^0.5.8",
|
||||
"@types/escape-regexp": "0.0.3",
|
||||
"@types/fluent-ffmpeg": "2.1.24",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/jsonld": "1.5.12",
|
||||
"@types/jsrsasign": "10.5.12",
|
||||
"@types/koa": "2.13.11",
|
||||
"@types/koa-bodyparser": "4.3.12",
|
||||
"@types/koa-cors": "0.0.5",
|
||||
"@types/koa-favicon": "2.1.3",
|
||||
"@types/koa-logger": "3.1.5",
|
||||
"@types/koa-mount": "4.0.5",
|
||||
"@types/koa-send": "4.1.6",
|
||||
"@types/koa__cors": "4.0.3",
|
||||
"@types/koa__multer": "2.0.7",
|
||||
"@types/koa__router": "12.0.4",
|
||||
"@types/mocha": "10.0.4",
|
||||
"@types/node": "20.9.0",
|
||||
"@types/node-fetch": "2.6.9",
|
||||
"@types/nodemailer": "6.4.14",
|
||||
"@types/oauth": "0.9.4",
|
||||
"@types/opencc-js": "^1.0.3",
|
||||
"@types/pg": "^8.10.9",
|
||||
"@types/probe-image-size": "^7.2.3",
|
||||
"@types/pug": "2.0.9",
|
||||
"@types/punycode": "2.1.2",
|
||||
"@types/qrcode": "1.5.5",
|
||||
"@types/qs": "6.9.10",
|
||||
"@types/random-seed": "0.3.5",
|
||||
"@types/ratelimiter": "3.4.6",
|
||||
"@types/rename": "1.0.7",
|
||||
"@types/sanitize-html": "2.9.4",
|
||||
"@types/semver": "7.5.5",
|
||||
"@types/sinonjs__fake-timers": "8.1.5",
|
||||
"@types/syslog-pro": "^1.0.3",
|
||||
"@types/tinycolor2": "1.4.6",
|
||||
"@types/tmp": "0.2.6",
|
||||
"@types/uuid": "9.0.7",
|
||||
"@types/web-push": "3.6.3",
|
||||
"@types/websocket": "1.0.9",
|
||||
"@types/ws": "8.5.9",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "^8.46.0",
|
||||
"execa": "6.1.0",
|
||||
"eslint": "^8.53.0",
|
||||
"execa": "8.0.1",
|
||||
"json5-loader": "4.0.1",
|
||||
"mocha": "10.2.0",
|
||||
"pug": "3.0.2",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"swc-loader": "^0.2.3",
|
||||
"ts-loader": "9.4.4",
|
||||
"ts-loader": "9.5.1",
|
||||
"ts-node": "10.9.1",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.1.6",
|
||||
"webpack": "^5.88.2",
|
||||
"ws": "8.13.0"
|
||||
"typescript": "5.2.2",
|
||||
"webpack": "^5.89.0",
|
||||
"ws": "8.14.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,9 @@ import semver from "semver";
|
|||
import Logger from "@/services/logger.js";
|
||||
import loadConfig from "@/config/load.js";
|
||||
import type { Config } from "@/config/types.js";
|
||||
import { lessThan } from "@/prelude/array.js";
|
||||
import { envOption } from "../env.js";
|
||||
import { envOption } from "@/env.js";
|
||||
import { showMachineInfo } from "@/misc/show-machine-info.js";
|
||||
import { db, initDb } from "../db/postgre.js";
|
||||
import { db, initDb } from "@/db/postgre.js";
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
|
@ -149,9 +148,7 @@ function showNodejsVersion(): void {
|
|||
|
||||
nodejsLogger.info(`Version ${process.version} detected.`);
|
||||
|
||||
const minVersion = fs
|
||||
.readFileSync(`${_dirname}/../../../../.node-version`, "utf-8")
|
||||
.trim();
|
||||
const minVersion = "v18.16.0";
|
||||
if (semver.lt(process.version, minVersion)) {
|
||||
nodejsLogger.error(`At least Node.js ${minVersion} required!`);
|
||||
process.exit(1);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import cluster from "node:cluster";
|
||||
import { initDb } from "../db/postgre.js";
|
||||
import config from "@/config/index.js";
|
||||
import { initDb } from "@/db/postgre.js";
|
||||
import os from "node:os";
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import config from "@/config/index.js";
|
||||
import {
|
||||
DB_MAX_NOTE_TEXT_LENGTH,
|
||||
DB_MAX_IMAGE_COMMENT_LENGTH,
|
||||
DB_MAX_NOTE_TEXT_LENGTH,
|
||||
} from "@/misc/hard-limits.js";
|
||||
|
||||
export const MAX_NOTE_TEXT_LENGTH = Math.min(
|
||||
|
@ -14,10 +14,8 @@ export const MAX_CAPTION_TEXT_LENGTH = Math.min(
|
|||
);
|
||||
|
||||
export const SECOND = 1000;
|
||||
export const SEC = 1000; // why do we need this duplicate here?
|
||||
export const MINUTE = 60 * SEC;
|
||||
export const MIN = 60 * SEC; // why do we need this duplicate here?
|
||||
export const HOUR = 60 * MIN;
|
||||
export const MINUTE = 60 * SECOND;
|
||||
export const HOUR = 60 * MINUTE;
|
||||
export const DAY = 24 * HOUR;
|
||||
|
||||
export const USER_ONLINE_THRESHOLD = 10 * MINUTE;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Xev from "xev";
|
||||
import { deliverQueue, inboxQueue } from "../queue/queues.js";
|
||||
import { deliverQueue, inboxQueue } from "@/queue/queues.js";
|
||||
|
||||
const ev = new Xev();
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import si from "systeminformation";
|
|||
import Xev from "xev";
|
||||
import * as osUtils from "os-utils";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import meilisearch from "../db/meilisearch.js";
|
||||
import meilisearch from "@/db/meilisearch.js";
|
||||
|
||||
const ev = new Xev();
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ function timestampToUnix(timestamp: string) {
|
|||
if (unix === 0) {
|
||||
// Try to parse the timestamp as JavaScript Date
|
||||
const date = Date.parse(timestamp);
|
||||
if (isNaN(date)) return 0;
|
||||
if (Number.isNaN(date)) return 0;
|
||||
unix = date / 1000;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,9 +74,10 @@ import { UserIp } from "@/models/entities/user-ip.js";
|
|||
import { NoteEdit } from "@/models/entities/note-edit.js";
|
||||
|
||||
import { entities as charts } from "@/services/chart/entities.js";
|
||||
import { envOption } from "../env.js";
|
||||
import { dbLogger } from "./logger.js";
|
||||
import { redisClient } from "./redis.js";
|
||||
|
||||
// TODO?: should we avoid importing things from built directory?
|
||||
import { nativeInitDatabase } from "native-utils/built/index.js";
|
||||
|
||||
const sqlLogger = dbLogger.createSubLogger("sql", "gray", false);
|
||||
|
|
2
packages/backend/src/global.d.ts
vendored
|
@ -1,2 +1,2 @@
|
|||
// rome-ignore lint/suspicious/noExplicitAny: i have no idea
|
||||
// biome-ignore lint/suspicious/noExplicitAny: i have no idea
|
||||
type FIXME = any;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Misskey Entry Point!
|
||||
* Firefish Entry Point
|
||||
*/
|
||||
|
||||
import { EventEmitter } from "node:events";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { redisClient } from "../db/redis.js";
|
||||
import { redisClient } from "@/db/redis.js";
|
||||
import { Mutex } from "redis-semaphore";
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import fetch from "node-fetch";
|
||||
import { URLSearchParams } from "node:url";
|
||||
import { getAgentByUrl } from "./fetch.js";
|
||||
import { getAgentByUrl } from "@/misc/fetch.js";
|
||||
import config from "@/config/index.js";
|
||||
|
||||
export async function verifyRecaptcha(secret: string, response: string) {
|
||||
|
|
|
@ -2,11 +2,11 @@ import type { Antenna } from "@/models/entities/antenna.js";
|
|||
import type { Note } from "@/models/entities/note.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { Blockings, UserProfiles } from "@/models/index.js";
|
||||
import { getFullApAccount } from "./convert-host.js";
|
||||
import { getFullApAccount } from "@/misc/convert-host.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import type { Packed } from "./schema.js";
|
||||
import { Cache } from "./cache.js";
|
||||
import { getWordHardMute } from "./check-word-mute.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { Cache } from "@/misc/cache.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
|
||||
const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5);
|
||||
const mutedWordsCache = new Cache<string[][] | undefined>("mutedWords", 60 * 5);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import twemoji from "twemoji-parser/dist/lib/regex.js";
|
||||
import twemoji from "@twemoji/parser/dist/lib/regex.js";
|
||||
const twemojiRegex = twemoji.default;
|
||||
|
||||
export const emojiRegex = new RegExp(`(${twemojiRegex.source})`);
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
// AID
|
||||
// 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さ2の[ノイズ文字列]
|
||||
|
||||
import * as crypto from "node:crypto";
|
||||
|
||||
const TIME2000 = 946684800000;
|
||||
let counter = crypto.randomBytes(2).readUInt16LE(0);
|
||||
|
||||
function getTime(time: number) {
|
||||
time = time - TIME2000;
|
||||
if (time < 0) time = 0;
|
||||
|
||||
return time.toString(36).padStart(8, "0");
|
||||
}
|
||||
|
||||
function getNoise() {
|
||||
return counter.toString(36).padStart(2, "0").slice(-2);
|
||||
}
|
||||
|
||||
export function genAid(date: Date): string {
|
||||
const t = date.getTime();
|
||||
if (isNaN(t)) throw "Failed to create AID: Invalid Date";
|
||||
counter++;
|
||||
return getTime(t) + getNoise();
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
const CHARS = "0123456789abcdef";
|
||||
|
||||
function getTime(time: number) {
|
||||
if (time < 0) time = 0;
|
||||
if (time === 0) {
|
||||
return CHARS[0];
|
||||
}
|
||||
|
||||
time += 0x800000000000;
|
||||
|
||||
return time.toString(16).padStart(12, CHARS[0]);
|
||||
}
|
||||
|
||||
function getRandom() {
|
||||
let str = "";
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export function genMeid(date: Date): string {
|
||||
return getTime(date.getTime()) + getRandom();
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
const CHARS = "0123456789abcdef";
|
||||
|
||||
// 4bit Fixed hex value 'g'
|
||||
// 44bit UNIX Time ms in Hex
|
||||
// 48bit Random value in Hex
|
||||
|
||||
function getTime(time: number) {
|
||||
if (time < 0) time = 0;
|
||||
if (time === 0) {
|
||||
return CHARS[0];
|
||||
}
|
||||
|
||||
return time.toString(16).padStart(11, CHARS[0]);
|
||||
}
|
||||
|
||||
function getRandom() {
|
||||
let str = "";
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export function genMeidg(date: Date): string {
|
||||
return `g${getTime(date.getTime())}${getRandom()}`;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
const CHARS = "0123456789abcdef";
|
||||
|
||||
function getTime(time: number) {
|
||||
if (time < 0) time = 0;
|
||||
if (time === 0) {
|
||||
return CHARS[0];
|
||||
}
|
||||
|
||||
time = Math.floor(time / 1000);
|
||||
|
||||
return time.toString(16).padStart(8, CHARS[0]);
|
||||
}
|
||||
|
||||
function getRandom() {
|
||||
let str = "";
|
||||
|
||||
for (let i = 0; i < 16; i++) {
|
||||
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export function genObjectId(date: Date): string {
|
||||
return getTime(date.getTime()) + getRandom();
|
||||
}
|
|
@ -383,6 +383,12 @@ export class Meta {
|
|||
})
|
||||
public ToSUrl: string | null;
|
||||
|
||||
@Column("jsonb", {
|
||||
default: [],
|
||||
nullable: false,
|
||||
})
|
||||
public moreUrls: [string, string][];
|
||||
|
||||
@Column("varchar", {
|
||||
length: 512,
|
||||
default: "https://git.joinfirefish.org/firefish/firefish",
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
ManyToOne,
|
||||
} from "typeorm";
|
||||
import { User } from "./user.js";
|
||||
import { Note } from "./note.js";
|
||||
import { id } from "../id.js";
|
||||
|
||||
@Entity()
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
import {
|
||||
PrimaryColumn,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
Column,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from "typeorm";
|
||||
import { Entity, Index, Column, PrimaryGeneratedColumn } from "typeorm";
|
||||
import { id } from "../id.js";
|
||||
import { Note } from "./note.js";
|
||||
import type { User } from "./user.js";
|
||||
|
||||
@Entity()
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import {} from "typeorm";
|
||||
import { db } from "@/db/postgre.js";
|
||||
|
||||
import { Announcement } from "./entities/announcement.js";
|
||||
import { AnnouncementRead } from "./entities/announcement-read.js";
|
||||
import { Instance } from "./entities/instance.js";
|
||||
import { Poll } from "./entities/poll.js";
|
||||
import { PollVote } from "./entities/poll-vote.js";
|
||||
import { Meta } from "./entities/meta.js";
|
||||
|
|
|
@ -2,12 +2,10 @@ import { db } from "@/db/postgre.js";
|
|||
import { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { awaitAll, Promiseable } from "@/prelude/await-all.js";
|
||||
import { awaitAll } from "@/prelude/await-all.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import config from "@/config/index.js";
|
||||
import { query, appendQuery } from "@/prelude/url.js";
|
||||
import { Meta } from "@/models/entities/meta.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { Users, DriveFolders } from "../index.js";
|
||||
import { deepClone } from "@/misc/clone.js";
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { In, Repository } from "typeorm";
|
||||
import { In } from "typeorm";
|
||||
import { Notification } from "@/models/entities/notification.js";
|
||||
import { awaitAll } from "@/prelude/await-all.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
|
@ -6,7 +6,6 @@ import type { Note } from "@/models/entities/note.js";
|
|||
import type { NoteReaction } from "@/models/entities/note-reaction.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { aggregateNoteEmojis, prefetchEmojis } from "@/misc/populate-emojis.js";
|
||||
import { notificationTypes } from "@/types.js";
|
||||
import { db } from "@/db/postgre.js";
|
||||
import {
|
||||
Users,
|
||||
|
|
|
@ -7,7 +7,6 @@ import type { Packed } from "@/misc/schema.js";
|
|||
import type { Promiseable } from "@/prelude/await-all.js";
|
||||
import { awaitAll } from "@/prelude/await-all.js";
|
||||
import { populateEmojis } from "@/misc/populate-emojis.js";
|
||||
import { getAntennas } from "@/misc/antenna-cache.js";
|
||||
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from "@/const.js";
|
||||
import { Cache } from "@/misc/cache.js";
|
||||
import { db } from "@/db/postgre.js";
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Notes } from "@/models/index.js";
|
|||
import { MoreThan } from "typeorm";
|
||||
import { index } from "@/services/note/create.js";
|
||||
import { Note } from "@/models/entities/note.js";
|
||||
import meilisearch from "../../../db/meilisearch.js";
|
||||
import meilisearch from "@/db/meilisearch.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("index-all-notes");
|
||||
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import type Bull from "bull";
|
||||
import * as fs from "node:fs";
|
||||
|
||||
import { ulid } from "ulid";
|
||||
import mime from "mime-types";
|
||||
import archiver from "archiver";
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { addFile } from "@/services/drive/add-file.js";
|
||||
import { format as dateFormat } from "date-fns";
|
||||
import { Users, Emojis } from "@/models/index.js";
|
||||
import {} from "@/queue/types.js";
|
||||
import { createTemp, createTempDir } from "@/misc/create-temp.js";
|
||||
import { downloadUrl } from "@/misc/download-url.js";
|
||||
import config from "@/config/index.js";
|
||||
|
|
|
@ -5,7 +5,7 @@ import * as Acct from "@/misc/acct.js";
|
|||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { Users, DriveFiles, Blockings } from "@/models/index.js";
|
||||
import { Users, DriveFiles } from "@/models/index.js";
|
||||
import type { DbUserImportJobData } from "@/queue/types.js";
|
||||
import block from "@/services/blocking/create.js";
|
||||
import { IsNull } from "typeorm";
|
||||
|
|
|
@ -5,7 +5,6 @@ import { queueLogger } from "../../logger.js";
|
|||
import type Bull from "bull";
|
||||
import { htmlToMfm } from "@/remote/activitypub/misc/html-to-mfm.js";
|
||||
import { resolveNote } from "@/remote/activitypub/models/note.js";
|
||||
import { Note } from "@/models/entities/note.js";
|
||||
import { uploadFromUrl } from "@/services/drive/upload-from-url.js";
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { Notes, NoteEdits } from "@/models/index.js";
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import type Bull from "bull";
|
||||
import { Notes, PollVotes } from "@/models/index.js";
|
||||
import { queueLogger } from "../logger.js";
|
||||
// import { queueLogger } from "../logger.js";
|
||||
import type { EndedPollNotificationJobData } from "@/queue/types.js";
|
||||
import { createNotification } from "@/services/create-notification.js";
|
||||
import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("ended-poll-notification");
|
||||
// unused
|
||||
// const logger = queueLogger.createSubLogger("ended-poll-notification");
|
||||
|
||||
export async function endedPollNotification(
|
||||
job: Bull.Job<EndedPollNotificationJobData>,
|
||||
|
|
|
@ -22,6 +22,7 @@ import { StatusError } from "@/misc/fetch.js";
|
|||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import type { UserPublickey } from "@/models/entities/user-publickey.js";
|
||||
import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
||||
import { verifySignature } from "@/remote/activitypub/check-fetch.js";
|
||||
|
||||
const logger = new Logger("inbox");
|
||||
|
||||
|
@ -114,6 +115,12 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
|
|||
);
|
||||
}
|
||||
|
||||
if (httpSignatureValidated) {
|
||||
if (!verifySignature(signature, authUser.key)) {
|
||||
return "skip: Invalid HTTP signature";
|
||||
}
|
||||
}
|
||||
|
||||
// また、signatureのsignerは、activity.actorと一致する必要がある
|
||||
if (!httpSignatureValidated || authUser.user.uri !== activity.actor) {
|
||||
// 一致しなくても、でもLD-Signatureがありそうならそっちも見る
|
||||
|
|
|
@ -4,7 +4,6 @@ import { UserProfiles } from "@/models/index.js";
|
|||
import { Not } from "typeorm";
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { verifyLink } from "@/services/fetch-rel-me.js";
|
||||
import config from "@/config/index.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("verify-links");
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { URL } from "node:url";
|
||||
import type Bull from "bull";
|
||||
import Logger from "@/services/logger.js";
|
||||
import type { WebhookDeliverJobData } from "../types.js";
|
||||
|
|
|
@ -8,7 +8,6 @@ import type {
|
|||
CacheableRemoteUser,
|
||||
CacheableUser,
|
||||
} from "@/models/entities/user.js";
|
||||
import { User } from "@/models/entities/user.js";
|
||||
|
||||
type Visibility = "public" | "home" | "followers" | "specified";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { URL } from "url";
|
||||
import httpSignature from "@peertube/http-signature";
|
||||
import httpSignature, { IParsedSignature } from "@peertube/http-signature";
|
||||
import config from "@/config/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
|
@ -9,6 +9,9 @@ import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
|||
import type { IncomingMessage } from "http";
|
||||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import type { UserPublickey } from "@/models/entities/user-publickey.js";
|
||||
import { verify } from "node:crypto";
|
||||
import { toSingle } from "@/prelude/array.js";
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
export async function hasSignature(req: IncomingMessage): Promise<string> {
|
||||
const meta = await fetchMeta();
|
||||
|
@ -28,10 +31,14 @@ export async function hasSignature(req: IncomingMessage): Promise<string> {
|
|||
export async function checkFetch(req: IncomingMessage): Promise<number> {
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
if (req.headers.host !== config.host) return 400;
|
||||
|
||||
let signature;
|
||||
|
||||
try {
|
||||
signature = httpSignature.parseRequest(req, { headers: [] });
|
||||
signature = httpSignature.parseRequest(req, {
|
||||
headers: ["(request-target)", "host", "date"],
|
||||
});
|
||||
} catch (e) {
|
||||
return 401;
|
||||
}
|
||||
|
@ -108,6 +115,8 @@ export async function checkFetch(req: IncomingMessage): Promise<number> {
|
|||
if (!httpSignatureValidated) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
return verifySignature(signature, authUser.key) ? 200 : 401;
|
||||
}
|
||||
return 200;
|
||||
}
|
||||
|
@ -130,3 +139,39 @@ export async function getSignatureUser(req: IncomingMessage): Promise<{
|
|||
keyId.hash = "";
|
||||
return await dbResolver.getAuthUserFromApId(getApId(keyId.toString()));
|
||||
}
|
||||
|
||||
export function verifySignature(
|
||||
sig: IParsedSignature,
|
||||
key: UserPublickey,
|
||||
): boolean {
|
||||
if (!["hs2019", "rsa-sha256"].includes(sig.algorithm.toLowerCase()))
|
||||
return false;
|
||||
try {
|
||||
return verify(
|
||||
"rsa-sha256",
|
||||
Buffer.from(sig.signingString, "utf8"),
|
||||
key.keyPem,
|
||||
Buffer.from(sig.params.signature, "base64"),
|
||||
);
|
||||
} catch {
|
||||
// Algo not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function verifyDigest(
|
||||
body: string,
|
||||
digest: string | string[] | undefined,
|
||||
): boolean {
|
||||
digest = toSingle(digest);
|
||||
if (
|
||||
body == null ||
|
||||
digest == null ||
|
||||
!digest.toLowerCase().startsWith("sha-256=")
|
||||
)
|
||||
return false;
|
||||
|
||||
return (
|
||||
createHash("sha256").update(body).digest("base64") === digest.substring(8)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ export function parseUri(value: string | IObject): UriParseResult {
|
|||
|
||||
export default class DbResolver {
|
||||
/**
|
||||
* AP Note => Misskey Note in DB
|
||||
* AP Note => Firefish Note in DB
|
||||
*/
|
||||
public async getNoteFromApId(value: string | IObject): Promise<Note | null> {
|
||||
const parsed = parseUri(value);
|
||||
|
@ -114,7 +114,7 @@ export default class DbResolver {
|
|||
}
|
||||
|
||||
/**
|
||||
* AP Person => Misskey User in DB
|
||||
* AP Person => Firefish User in DB
|
||||
*/
|
||||
public async getUserFromApId(
|
||||
value: string | IObject,
|
||||
|
@ -147,7 +147,7 @@ export default class DbResolver {
|
|||
}
|
||||
|
||||
/**
|
||||
* AP KeyId => Misskey User and Key
|
||||
* AP KeyId => Firefish User and Key
|
||||
*/
|
||||
public async getAuthUserFromKeyId(keyId: string): Promise<{
|
||||
user: CacheableRemoteUser;
|
||||
|
@ -181,7 +181,7 @@ export default class DbResolver {
|
|||
}
|
||||
|
||||
/**
|
||||
* AP Actor id => Misskey User and Key
|
||||
* AP Actor id => Firefish User and Key
|
||||
*/
|
||||
public async getAuthUserFromApId(uri: string): Promise<{
|
||||
user: CacheableRemoteUser;
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { IRead } from "../type.js";
|
|||
import { getApId } from "../type.js";
|
||||
import { isSelfHost, extractDbHost } from "@/misc/convert-host.js";
|
||||
import { MessagingMessages } from "@/models/index.js";
|
||||
import { readUserMessagingMessage } from "../../../server/api/common/read-messaging-message.js";
|
||||
import { readUserMessagingMessage } from "@/server/api/common/read-messaging-message.js";
|
||||
|
||||
export const performReadActivity = async (
|
||||
actor: CacheableRemoteUser,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import unfollow from "@/services/following/delete.js";
|
||||
import cancelRequest from "@/services/following/requests/cancel.js";
|
||||
import type { IAccept } from "../../type.js";
|
||||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import { Followings } from "@/models/index.js";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as mfm from "mfm-js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { toHtml } from "../../../mfm/to-html.js";
|
||||
import { toHtml } from "@/mfm/to-html.js";
|
||||
|
||||
export default function (note: Note) {
|
||||
if (!note.text) return "";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { IObject } from "../type.js";
|
||||
import { extractApHashtagObjects } from "../models/tag.js";
|
||||
import { fromHtml } from "../../../mfm/from-html.js";
|
||||
import { fromHtml } from "@/mfm/from-html.js";
|
||||
|
||||
export function htmlToMfm(html: string, tag?: IObject | IObject[]) {
|
||||
const hashtagNames = extractApHashtagObjects(tag)
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { uploadFromUrl } from "@/services/drive/upload-from-url.js";
|
||||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import { IRemoteUser } from "@/models/entities/user.js";
|
||||
import Resolver from "../resolver.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { apLogger } from "../logger.js";
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { DriveFiles, Users } from "@/models/index.js";
|
||||
import { DriveFiles } from "@/models/index.js";
|
||||
import { truncate } from "@/misc/truncate.js";
|
||||
import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js";
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import promiseLimit from "promise-limit";
|
||||
import { toArray, unique } from "@/prelude/array.js";
|
||||
import type { CacheableUser } from "@/models/entities/user.js";
|
||||
import { User } from "@/models/entities/user.js";
|
||||
import type { IObject, IApMention } from "../type.js";
|
||||
import { isMention } from "../type.js";
|
||||
import Resolver from "../resolver.js";
|
||||
|
|
|
@ -6,10 +6,7 @@ import post from "@/services/note/create.js";
|
|||
import { extractMentionedUsers } from "@/services/note/create.js";
|
||||
import { resolvePerson } from "./person.js";
|
||||
import { resolveImage } from "./image.js";
|
||||
import type {
|
||||
ILocalUser,
|
||||
CacheableRemoteUser,
|
||||
} from "@/models/entities/user.js";
|
||||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import { htmlToMfm } from "../misc/html-to-mfm.js";
|
||||
import { extractApHashtags } from "./tag.js";
|
||||
import { unique, toArray, toSingle } from "@/prelude/array.js";
|
||||
|
@ -52,7 +49,6 @@ import { In } from "typeorm";
|
|||
import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js";
|
||||
import { truncate } from "@/misc/truncate.js";
|
||||
import { type Size, getEmojiSize } from "@/misc/emoji-meta.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { langmap } from "@/misc/langmap.js";
|
||||
|
||||
const logger = apLogger;
|
||||
|
|
|
@ -8,7 +8,6 @@ import { updateUsertags } from "@/services/update-hashtag.js";
|
|||
import {
|
||||
Users,
|
||||
Instances,
|
||||
DriveFiles,
|
||||
Followings,
|
||||
UserProfiles,
|
||||
UserPublickeys,
|
||||
|
@ -33,8 +32,8 @@ import { publishInternalEvent } from "@/services/stream.js";
|
|||
import { db } from "@/db/postgre.js";
|
||||
import { apLogger } from "../logger.js";
|
||||
import { htmlToMfm } from "../misc/html-to-mfm.js";
|
||||
import { fromHtml } from "../../../mfm/from-html.js";
|
||||
import type { IActor, IObject, IApPropertyValue } from "../type.js";
|
||||
import { fromHtml } from "@/mfm/from-html.js";
|
||||
import type { IActor, IObject } from "../type.js";
|
||||
import {
|
||||
isCollectionOrOrderedCollection,
|
||||
isCollection,
|
||||
|
@ -313,7 +312,9 @@ export async function createPerson(
|
|||
await transactionalEntityManager.save(
|
||||
new UserProfile({
|
||||
userId: user.id,
|
||||
description: person.summary
|
||||
description: person._misskey_summary
|
||||
? truncate(person._misskey_summary, summaryLength)
|
||||
: person.summary
|
||||
? htmlToMfm(truncate(person.summary, summaryLength), person.tag)
|
||||
: null,
|
||||
url: url,
|
||||
|
@ -456,7 +457,7 @@ export async function updatePerson(
|
|||
|
||||
const emojiNames = emojis.map((emoji) => emoji.name);
|
||||
|
||||
const { fields } = analyzeAttachments(person.attachment || []);
|
||||
const fields = analyzeAttachments(person.attachment || []);
|
||||
|
||||
const tags = extractApHashtags(person.tag)
|
||||
.map((tag) => normalizeForSearch(tag))
|
||||
|
@ -589,7 +590,9 @@ export async function updatePerson(
|
|||
{
|
||||
url: url,
|
||||
fields,
|
||||
description: person.summary
|
||||
description: person._misskey_summary
|
||||
? truncate(person._misskey_summary, summaryLength)
|
||||
: person.summary
|
||||
? htmlToMfm(truncate(person.summary, summaryLength), person.tag)
|
||||
: null,
|
||||
birthday: bday ? bday[0] : null,
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
import config from "@/config/index.js";
|
||||
import { IObject, IActivity } from "@/remote/activitypub/type.js";
|
||||
import type { ILocalUser } from "@/models/entities/user.js";
|
||||
import { IRemoteUser } from "@/models/entities/user.js";
|
||||
import { getInstanceActor } from "@/services/instance-actor.js";
|
||||
|
||||
// to anonymise reporters, the reporting actor must be a system user
|
||||
// object has to be a uri or array of uris
|
||||
|
|
|
@ -43,6 +43,7 @@ export const renderActivity = (x: any): IActivity | null => {
|
|||
_misskey_talk: "misskey:_misskey_talk",
|
||||
_misskey_reaction: "misskey:_misskey_reaction",
|
||||
_misskey_votes: "misskey:_misskey_votes",
|
||||
_misskey_summary: "misskey:_misskey_summary",
|
||||
isCat: "misskey:isCat",
|
||||
// Fedibird
|
||||
fedibird: "http://fedibird.com/ns#",
|
||||
|
|
|
@ -74,6 +74,7 @@ export async function renderPerson(user: ILocalUser) {
|
|||
summary: profile.description
|
||||
? toHtml(mfm.parse(profile.description))
|
||||
: null,
|
||||
_misskey_summary: profile.description,
|
||||
icon: avatar ? renderImage(avatar) : null,
|
||||
image: banner ? renderImage(banner) : null,
|
||||
tag,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import config from "@/config/index.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { ILocalUser } from "@/models/entities/user.js";
|
||||
|
||||
export default (object: any, user: { id: User["id"] }) => {
|
||||
if (object == null) return null;
|
||||
|
|
|
@ -7,13 +7,7 @@ import { extractDbHost, isSelfHost } from "@/misc/convert-host.js";
|
|||
import { signedGet } from "./request.js";
|
||||
import type { IObject, ICollection, IOrderedCollection } from "./type.js";
|
||||
import { isCollectionOrOrderedCollection, getApId } from "./type.js";
|
||||
import {
|
||||
FollowRequests,
|
||||
Notes,
|
||||
NoteReactions,
|
||||
Polls,
|
||||
Users,
|
||||
} from "@/models/index.js";
|
||||
import { Notes, NoteReactions, Polls, Users } from "@/models/index.js";
|
||||
import { parseUri } from "./db-resolver.js";
|
||||
import renderNote from "@/remote/activitypub/renderer/note.js";
|
||||
import { renderLike } from "@/remote/activitypub/renderer/like.js";
|
||||
|
|
|
@ -205,6 +205,7 @@ export interface IActor extends IObject {
|
|||
};
|
||||
"vcard:bday"?: string;
|
||||
"vcard:Address"?: string;
|
||||
_misskey_summary?: string;
|
||||
}
|
||||
|
||||
export const isCollection = (object: IObject): object is ICollection =>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Router from "@koa/router";
|
||||
import json from "koa-json-body";
|
||||
import bodyParser from "koa-bodyparser";
|
||||
import httpSignature from "@peertube/http-signature";
|
||||
|
||||
import { In, IsNull, Not } from "typeorm";
|
||||
|
@ -9,7 +9,7 @@ import renderKey from "@/remote/activitypub/renderer/key.js";
|
|||
import { renderPerson } from "@/remote/activitypub/renderer/person.js";
|
||||
import renderEmoji from "@/remote/activitypub/renderer/emoji.js";
|
||||
import { inbox as processInbox } from "@/queue/index.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { isSelfHost } from "@/misc/convert-host.js";
|
||||
import {
|
||||
Notes,
|
||||
Users,
|
||||
|
@ -22,8 +22,8 @@ import { renderLike } from "@/remote/activitypub/renderer/like.js";
|
|||
import { getUserKeypair } from "@/misc/keypair-store.js";
|
||||
import {
|
||||
checkFetch,
|
||||
hasSignature,
|
||||
getSignatureUser,
|
||||
verifyDigest,
|
||||
} from "@/remote/activitypub/check-fetch.js";
|
||||
import { getInstanceActor } from "@/services/instance-actor.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
|
@ -33,6 +33,8 @@ import Following from "./activitypub/following.js";
|
|||
import Followers from "./activitypub/followers.js";
|
||||
import Outbox, { packActivity } from "./activitypub/outbox.js";
|
||||
import { serverLogger } from "./index.js";
|
||||
import config from "@/config/index.js";
|
||||
import Koa from "koa";
|
||||
|
||||
// Init router
|
||||
const router = new Router();
|
||||
|
@ -40,15 +42,27 @@ const router = new Router();
|
|||
//#region Routing
|
||||
|
||||
function inbox(ctx: Router.RouterContext) {
|
||||
if (ctx.req.headers.host !== config.host) {
|
||||
ctx.status = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
let signature;
|
||||
|
||||
try {
|
||||
signature = httpSignature.parseRequest(ctx.req, { headers: [] });
|
||||
signature = httpSignature.parseRequest(ctx.req, {
|
||||
headers: ["(request-target)", "digest", "host", "date"],
|
||||
});
|
||||
} catch (e) {
|
||||
ctx.status = 401;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!verifyDigest(ctx.request.rawBody, ctx.headers.digest)) {
|
||||
ctx.status = 401;
|
||||
return;
|
||||
}
|
||||
|
||||
processInbox(ctx.request.body, signature);
|
||||
|
||||
ctx.status = 202;
|
||||
|
@ -73,9 +87,23 @@ export function setResponseType(ctx: Router.RouterContext) {
|
|||
}
|
||||
}
|
||||
|
||||
async function parseJsonBodyOrFail(ctx: Router.RouterContext, next: Koa.Next) {
|
||||
const koaBodyParser = bodyParser({
|
||||
enableTypes: ["json"],
|
||||
detectJSON: () => true,
|
||||
});
|
||||
|
||||
try {
|
||||
await koaBodyParser(ctx, next);
|
||||
} catch {
|
||||
ctx.status = 400;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// inbox
|
||||
router.post("/inbox", json(), inbox);
|
||||
router.post("/users/:user/inbox", json(), inbox);
|
||||
router.post("/inbox", parseJsonBodyOrFail, inbox);
|
||||
router.post("/users/:user/inbox", parseJsonBodyOrFail, inbox);
|
||||
|
||||
// note
|
||||
router.get("/notes/:note", async (ctx, next) => {
|
||||
|
|
|
@ -28,13 +28,19 @@ export default async (ctx: Router.RouterContext) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const pinings = await UserNotePinings.find({
|
||||
const pinning = await UserNotePinings.find({
|
||||
where: { userId: user.id },
|
||||
order: { id: "DESC" },
|
||||
});
|
||||
|
||||
const pinnedNotes = await Promise.all(
|
||||
pinings.map((pining) => Notes.findOneByOrFail({ id: pining.noteId })),
|
||||
const pinnedNotes = (
|
||||
await Promise.all(
|
||||
pinning.map((pinnedNote) =>
|
||||
this.notesRepository.findOneByOrFail({ id: pinnedNote.noteId }),
|
||||
),
|
||||
)
|
||||
).filter(
|
||||
(note) => !note.localOnly && ["public", "home"].includes(note.visibility),
|
||||
);
|
||||
|
||||
const renderedNotes = await Promise.all(
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { performance } from "perf_hooks";
|
||||
import type Koa from "koa";
|
||||
import type { CacheableLocalUser } from "@/models/entities/user.js";
|
||||
import { User } from "@/models/entities/user.js";
|
||||
import type { AccessToken } from "@/models/entities/access-token.js";
|
||||
import { getIpHash } from "@/misc/get-ip-hash.js";
|
||||
import { limiter } from "./limiter.js";
|
||||
|
@ -10,7 +9,6 @@ import endpoints from "./endpoints.js";
|
|||
import compatibility from "./compatibility.js";
|
||||
import { ApiError } from "./error.js";
|
||||
import { apiLogger } from "./logger.js";
|
||||
import type { AccessToken } from "@/models/entities/access-token.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
|
||||
const accessDenied = {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import * as fs from "node:fs";
|
||||
import Ajv from "ajv";
|
||||
import type { CacheableLocalUser } from "@/models/entities/user.js";
|
||||
import { ILocalUser } from "@/models/entities/user.js";
|
||||
import type { Schema, SchemaType } from "@/misc/schema.js";
|
||||
import type { AccessToken } from "@/models/entities/access-token.js";
|
||||
import type { IEndpointMeta } from "./endpoints.js";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from "../../define.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { AbuseUserReports } from "@/models/index.js";
|
||||
import { makePaginationQuery } from "../../common/make-pagination-query.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["admin"],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from "../../../define.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { signup } from "../../../common/signup.js";
|
||||
import { signup } from "@/server/api/common/signup.js";
|
||||
import { IsNull } from "typeorm";
|
||||
|
||||
export const meta = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import define from "../../../define.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { doPostSuspend } from "@/services/suspend-user.js";
|
||||
import { publishUserEvent } from "@/services/stream.js";
|
||||
|
|
|
@ -2,7 +2,7 @@ import config from "@/config/index.js";
|
|||
import { Meta } from "@/models/entities/meta.js";
|
||||
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
||||
import { db } from "@/db/postgre.js";
|
||||
import define from "../../../define.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["admin"],
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import define from "../../../define.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { Ads } from "@/models/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
|
||||
|
|