Compare commits

..

1 Commits

Author SHA1 Message Date
6fdb311811 Custom configuration for rudeshark.net 2023-12-30 00:49:07 +01:00
730 changed files with 3074 additions and 3210 deletions

1
.node-version Normal file
View File

@ -0,0 +1 @@
v18.16.0

1
.npmrc Normal file
View File

@ -0,0 +1 @@
use-lockfile-v6=true

4
.vsls.json Normal file
View File

@ -0,0 +1,4 @@
{
"$schema": "http://json.schemastore.org/vsls",
"gitignore": "exclude"
}

View File

@ -1,5 +1,5 @@
## Install dev and compilation dependencies, build files
FROM node:20-slim as build
FROM node:20 as build
WORKDIR /firefish
# Install compilation dependencies
@ -48,11 +48,11 @@ RUN env NODE_ENV=production sh -c "pnpm run --filter '!native-utils' build && pn
RUN pnpm i --prod --frozen-lockfile
## Runtime container
FROM node:20-slim
FROM node:20
WORKDIR /firefish
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends libvips-dev zip unzip tini ffmpeg
RUN apt-get update && apt-get install -y libvips-dev zip unzip tini ffmpeg
COPY . ./

View File

@ -4,19 +4,18 @@ services:
web:
# 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
image: registry.joinfirefish.org/firefish/firefish:beta-amd64
container_name: rudeshark_web
restart: unless-stopped
depends_on:
- db
- redis
### Uncomment one of the following to use a search engine
# - meilisearch
- meilisearch
# - sonic
ports:
- "3000:3000"
- "127.0.0.1:8071:3000"
networks:
- calcnet
- firenet
# - web
environment:
NODE_ENV: production
@ -26,39 +25,41 @@ services:
redis:
restart: unless-stopped
image: docker.io/redis:7.0-alpine
container_name: firefish_redis
image: docker.io/redis:7-alpine
container_name: rudeshark_redis
networks:
- calcnet
- firenet
volumes:
- ./redis:/data
db:
restart: unless-stopped
image: docker.io/postgres:12.2-alpine
container_name: firefish_db
image: docker.io/postgres:15-alpine
container_name: rudeshark_db
networks:
- calcnet
- firenet
env_file:
- .config/docker.env
volumes:
- ./db:/var/lib/postgresql/data
- ./postgresql:/var/lib/postgresql/data
### Only one of the below should be used.
### Meilisearch is better overall, but resource-intensive. Sonic is a very light full text search engine.
# meilisearch:
# container_name: meilisearch
# image: getmeili/meilisearch:v1.1.1
# environment:
# - MEILI_ENV=${MEILI_ENV:-development}
meilisearch:
container_name: rudeshark_meilisearch
image: getmeili/meilisearch:v1.1.1
environment:
- MEILI_ENV=production
env_file:
- ./.config/meilisearch.env
# ports:
# - "7700:7700"
# networks:
# - calcnet
# volumes:
# - ./meili_data:/meili_data
# restart: unless-stopped
# - "127.0.0.1:7706:7700"
networks:
- firenet
volumes:
- ./meilisearch/data:/meili_data
restart: unless-stopped
# sonic:
# restart: unless-stopped
@ -66,13 +67,16 @@ services:
# logging:
# driver: none
# networks:
# - calcnet
# - firenet
# volumes:
# - ./sonic:/var/lib/sonic/store
# - ./sonic/config.cfg:/etc/sonic.cfg
networks:
calcnet:
firenet:
ipam:
config:
- subnet: 172.22.22.0/24
# web:
# external:
# name: web

View File

@ -475,5 +475,3 @@ _preferencesBackups:
editWidgetsExit: Готово
done: Готово
emailRequiredForSignup: Изискване за адрес на е-поща за регистриране
preview: Преглед
privacy: Поверителност

View File

@ -895,7 +895,7 @@ nUsersRead: llegit per {n}
agreeTo: Estic d'acord amb {0}
activity: Activitat
home: Inici
remoteUserCaution: La informació dels usuaris remots és incompleta.
remoteUserCaution: La informació dels usuaris remots pot estar 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 usuaris descoberts
recentlyDiscoveredUsers: Nous suaris descoberts
administrator: Administrador
token: Token
registerSecurityKey: Registreu una clau de seguretat
@ -2212,9 +2212,3 @@ 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.

View File

@ -1156,8 +1156,6 @@ 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

View File

@ -1219,13 +1219,6 @@ _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."
@ -2169,15 +2162,3 @@ 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

View File

@ -355,24 +355,3 @@ driveFileDeleteConfirm: Tes a certeza de querer eliminar o ficheiro "{name}"? Va
ser retirado de todas as publicacións nas que estea como anexo.
inputNewFolderName: Escribe o novo nome do cartafol
hasChildFilesOrFolders: Como o cartafol non está baleiro, non pode ser eliminado.
dayX: '{day}'
reloadConfirm: Queres actualizar a cronoloxía?
watch: Ver
normal: Normal
monthX: '{month}'
instanceDescription: Descrición do servidor
disconnectedFromServer: Perdeuse a conexión co servidor
enableLocalTimeline: Activar cronoloxía local
reload: Actualizar
doNothing: Ignorar
instanceName: Nome do servidor
yearX: '{year}'
thisYear: Ano
unwatch: Deixar de ver
tosUrl: URL dos Termos do Servizo
thisMonth: Mes
pages: Páxinas
reject: Rexeitar
accept: Aceptar
maintainerName: Mantido por
today: Hoxe

View File

@ -1,3 +1 @@
_lang_: "हिन्दी"
headlineFirefish: एक ओपन सोर्स , डिसेंट्रलाइज़्ड सोशल मीडिया प्लेटफ़ॉर्म जो हमेशा के
लिए मुफ़्त है! 🚀

View File

@ -2193,8 +2193,3 @@ 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.

View File

@ -2182,8 +2182,3 @@ 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.

View File

@ -981,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生成を有効にする"
@ -994,8 +994,6 @@ addRe: "閲覧注意の投稿への返信で、注釈の先頭に\"re:\"を追
languageForTranslation: "投稿翻訳に使用する言語"
detectPostLanguage: "投稿の言語を自動検出し、外国語の投稿に翻訳ボタンを表示する"
iconSet: "アイコンのスタイル"
useEmojiCdn: "CDNのTwemojiを利用する"
useEmojiCdnDescription: "サーバー上に保存されているTwemojiのアセットの代わりに、JSDelivr CDNから配信されたものを用います。"
_sensitiveMediaDetection:
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てられます。サーバーの負荷が少し増えます。"
@ -1033,7 +1031,7 @@ _ad:
_forgotPassword:
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"
ifNoEmail: "メールアドレスを登録していない場合は、管理者までお問い合わせください。"
contactAdmin: "このサーバーではメールアドレスの登録がサポートされていないため、パスワードリセットを行う場合は管理者までお問い合わせください。"
contactAdmin: "このインスタンスではメールアドレスの登録がサポートされていないため、パスワードリセットを行う場合は管理者までお問い合わせください。"
_gallery:
my: "自分の投稿"
liked: "いいねした投稿"

View File

@ -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,17 +1444,12 @@ _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: なんかおましたか?
@ -1464,7 +1459,6 @@ _postForm:
f: あんさん書くんを待っとるんどす...
a: いまなにしとん?
flagSpeakAsCat: 猫弁で喋る
flagSpeakAsCatDescription: オンにすると、ワレの投稿の「な」「na」を「にゃ」「nya」に変換したるで。
flagSpeakAsCatDescription: オンにすると、ワレの投稿の「な」を「にゃ」に変換したるで。
welcomeBackWithName: おおきに、{name}はん
migration: アカウントの引っ越し
makeReactionsPublicDescription: あんたが付けたリアクションの一覧をみんなにも見せたるで。

View File

@ -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: "За день"

View File

@ -1,26 +1,25 @@
_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: "ไทม์ไลน์"
@ -29,14 +28,14 @@ login: "เข้าสู่ระบบ"
loggingIn: "กำลังเข้าสู่ระบบ"
logout: "ออกจากระบบ"
signup: "สร้างบัญชีผู้ใช้"
uploading: "กำลังอัโหลด..."
uploading: "กำลังอัโหลด..."
save: "บันทึก"
users: "ผู้ใช้งาน"
addUser: "เพิ่มผู้ใช้"
favorite: "เพิ่มลงในรายการโปรด"
favorite: "รายการโปรด"
favorites: "รายการโปรด"
unfavorite: "ลบออกจากรายการโปรด"
favorited: "เพิ่มในรายการโปรดแล้ว"
favorited: "เพิ่มแล้วในรายการโปรด"
alreadyFavorited: "เพิ่มในรายการโปรดอยู่แล้ว"
cantFavorite: "ไม่สามารถเพิ่มในรายการโปรดได้"
pin: "ปักหมุดไปยังโปรไฟล์"
@ -56,22 +55,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: "กำลังติดตาม"
@ -80,76 +79,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: "เนื้อหาที่ละเอียดอ่อน"
sensitive: "เนื้อหาที่ละเอียดอ่อน NSFW"
add: "เพิ่ม"
reaction: "รีแอคชัน"
reactionSetting: "รีแอคชันที่จะแสดงผลในตัวเลือกการรีแอคชัน"
reactionSettingDescription2: "ลากเพื่อจัดลำดับใหม่ คลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม"
reaction: "รีแอคชัน"
reactionSetting: "รีแอคชั่นไปยังแสดงผลในตัวเลือกการรีแอคชัน"
reactionSettingDescription2: "กดลากเพื่อจัดลำดับใหม่ กดคลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม"
rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นโพสต์"
attachCancel: "ลบไฟล์ที่แนบมา"
attachCancel: "ลบไฟล์ออกที่แนบมา"
markAsSensitive: "ทำเครื่องหมายว่าละเอียดอ่อน"
unmarkAsSensitive: "ยกเลิกทำเครื่องหมายว่าละเอียดอ่อน"
unmarkAsSensitive: "ยกเลิกทำเครื่องหมายเป็น NSFW"
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: "เพิ่มบัญชี"
@ -1246,28 +1245,22 @@ _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: ในโหมดแมว โพสต์ของคุณจะถูกทำให้เป็นแมว

View File

@ -22,7 +22,7 @@ otherSettings: "其他設定"
openInWindow: "在新視窗開啟"
profile: "個人檔案"
timeline: "時間軸"
noAccountDescription: "此使用者尚未自我介紹。"
noAccountDescription: "此用戶還沒有自我介紹。"
login: "登入"
loggingIn: "登入中"
logout: "登出"
@ -127,8 +127,8 @@ block: "封鎖"
unblock: "解除封鎖"
suspend: "凍結"
unsuspend: "解除凍結"
blockConfirm: "確定要封鎖此使用者嗎"
unblockConfirm: "確定要解除封鎖此使用者嗎"
blockConfirm: "確定要封鎖此用戶"
unblockConfirm: "確定解除封鎖此用戶"
suspendConfirm: "確定凍結此帳號?"
unsuspendConfirm: "確定解凍此帳號?"
selectList: "選擇清單"
@ -145,12 +145,12 @@ addEmoji: "加入表情符號"
settingGuide: "推薦設定"
cacheRemoteFiles: "快取遠端檔案"
cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間,但資料會因直接連線從而產生額外數據花費。"
flagAsBot: "標記此帳號為自動化帳號"
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。此選項將作為一個標示以幫助其他開發者防止自動化帳號之間產生無限互動的行為並會調整Firefish內部系統將此帳號識別為自動化帳號。"
flagAsBot: "標記此帳號是機器人"
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後會作為標示幫助其他開發者防止機器人之間產生無限互動的行為並會調整Firefish內部系統將本帳戶識別為機器人。"
flagAsCat: "你是喵咪嗎w😺"
flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示!"
flagShowTimelineReplies: "在時間軸上顯示貼文的回覆"
flagShowTimelineRepliesDescription: "啟用後,時間軸除了顯示使用者的貼文之外,也會顯示使用者對其他貼文的回覆。"
flagShowTimelineRepliesDescription: "啟用時,時間軸除了顯示用戶的貼文以外,還會顯示用戶對其他貼文的回覆。"
autoAcceptFollowed: "自動准予追隨中使用者的追隨請求"
addAccount: "添加帳戶"
loginFailed: "登入失敗"
@ -163,7 +163,7 @@ searchWith: "搜尋: {q}"
youHaveNoLists: "你沒有任何清單"
followConfirm: "你真的要追隨 「{name}」 嗎?"
proxyAccount: "代理帳戶"
proxyAccountDescription: "代理帳戶是在某些情況下代替本地使用者追隨遠端使用者的帳戶。例如,當本地使用者將遠端使用者加入清單時,若沒有其他本地使用者追隨該遠端使用者,該遠端使用者的動態將不會發送到本地伺服器,因此將以代理帳戶代為追隨。"
proxyAccountDescription: "代理帳戶是在某些情況下充當其他伺服器用戶的帳戶。例如,當使用者將一個來自其他伺服器的帳戶放在列表中時,由於沒有其他使用者追蹤該帳戶,該指令不會傳送到該伺服器上,因此會由代理帳戶追蹤。"
host: "主機"
selectUser: "選取使用者"
recipient: "收件人"
@ -199,8 +199,8 @@ clearCachedFilesConfirm: "確定要清除所有遠端暫存資料嗎?"
blockedInstances: "已封鎖的伺服器"
blockedInstancesDescription: "請逐行輸入需要封鎖的伺服器。已封鎖的伺服器將無法與本伺服器進行通訊。"
muteAndBlock: "靜音和封鎖"
mutedUsers: "已靜音的使用者"
blockedUsers: "已封鎖的使用者"
mutedUsers: "已靜音用戶"
blockedUsers: "已封鎖用戶"
noUsers: "沒有任何使用者"
editProfile: "編輯個人檔案"
noteDeleteConfirm: "確定刪除此貼文嗎?"
@ -222,7 +222,7 @@ publishing: "直播中"
notResponding: "沒有回應"
instanceFollowing: "追蹤伺服器"
instanceFollowers: "伺服器的追蹤者"
instanceUsers: "此伺服器的使用者"
instanceUsers: "此伺服器的用戶"
changePassword: "修改密碼"
security: "安全性"
retypedNotMatch: "兩次輸入不一致。"
@ -262,7 +262,7 @@ agreeTo: "我同意{0}"
tos: "使用條款"
start: "開始"
home: "首頁"
remoteUserCaution: "遠端使用者的資訊並不完整。"
remoteUserCaution: "由於該使用者來自遠端實例,因此資料可能是非即時的。"
activity: "動態"
images: "圖片"
birthday: "生日"
@ -330,14 +330,14 @@ disablingTimelinesInfo: "即使您關閉了時間軸功能,管理員和板主
registration: "註冊"
enableRegistration: "開啟新使用者註冊"
invite: "邀請"
driveCapacityPerLocalAccount: "每個本地使用者的雲端容量"
driveCapacityPerRemoteAccount: "每個遠端使用者的雲端容量"
driveCapacityPerLocalAccount: "每個本地用戶的雲端空間大小"
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端容量"
inMb: "以MB為單位"
iconUrl: "圖標網址"
bannerUrl: "橫幅圖像網址"
backgroundImageUrl: "背景圖片的來源網址"
basicInfo: "基本資訊"
pinnedUsers: "置頂的使用者"
pinnedUsers: "置頂用戶"
pinnedUsersDescription: "在「探索」頁面中使用換行標記想要置頂的使用者。"
pinnedPages: "已釘選的頁面"
pinnedPagesDescription: "輸入要固定至伺服器首頁的頁面路徑,一行一個。"
@ -362,14 +362,14 @@ antennaKeywordsDescription: "用空格分隔指定AND、用換行符分隔指定
notifyAntenna: "通知有新貼文"
withFileAntenna: "僅帶有附件的貼文"
enableServiceworker: "開啟 ServiceWorker"
antennaUsersDescription: "指定使用者名稱,一行一個"
antennaUsersDescription: "指定用換行符分隔的用戶名"
caseSensitive: "區分大小寫"
withReplies: "包含回覆"
connectedTo: "您的帳戶已連接到以下社交帳戶"
notesAndReplies: "貼文與回覆"
withFiles: "附件"
silence: "禁言"
silenceConfirm: "確定要禁言此使用者嗎?"
silenceConfirm: "確定要禁言此用戶嗎?"
unsilence: "解除禁言"
unsilenceConfirm: "確定要解除禁言嗎?"
popularUsers: "熱門使用者"
@ -537,7 +537,7 @@ deleteAllFilesConfirm: "確定要刪除所有檔案嗎?"
removeAllFollowing: "解除所有追蹤"
removeAllFollowingDescription: "解除{host}所有的追蹤。在伺服器不再存在時執行。"
userSuspended: "此使用者已被停用。"
userSilenced: "該使用者已被禁言。"
userSilenced: "該用戶已被禁言。"
yourAccountSuspendedTitle: "帳戶已被凍結"
yourAccountSuspendedDescription: "由於違反了伺服器的服務條款或其他原因,該帳戶已被凍結。 您可以與管理員連繫以了解更多訊息。 請不要創建一個新的帳戶。"
menu: "選單"
@ -660,7 +660,7 @@ repliesCount: "回覆數量"
renotesCount: "轉發數量"
repliedCount: "回覆數量"
renotedCount: "轉發次數"
followingCount: "追隨中的使用者數量"
followingCount: "正在跟隨的用戶數量"
followersCount: "跟隨者數量"
sentReactionsCount: "反應發送次數"
receivedReactionsCount: "反應收到次數"
@ -700,7 +700,7 @@ needReloadToApply: "必須重新載入才會生效。"
showTitlebar: "顯示標題列"
clearCache: "清除快取資料"
onlineUsersCount: "{n}人正在線上"
nUsers: "{n}使用者"
nUsers: "{n}用戶"
nNotes: "{n}貼文"
sendErrorReports: "傳送錯誤報告"
sendErrorReportsDescription: "開啟後,錯誤出現時將會與 Firefish 分享詳細紀錄,對於 Firefish 的開發會有非常大的幫助。\n
@ -746,7 +746,7 @@ addDescription: "添加描述"
userPagePinTip: "在貼文的選單中選擇\"置頂\",即可置頂該貼文至您的個人檔案頁面。"
notSpecifiedMentionWarning: "此貼文有未指定的提及"
info: "資訊"
userInfo: "使用者資訊"
userInfo: "用戶資料"
unknown: "未知"
onlineStatus: "在線狀態"
hideOnlineStatus: "隱藏在線狀態"
@ -891,7 +891,7 @@ cannotUploadBecauseNoFreeSpace: "由於雲端硬碟沒有可用空間,因此
beta: "Beta"
enableAutoSensitive: "自動NSFW判定"
enableAutoSensitiveDescription: "如可用,請利用機器學習在媒體上自動設置 NSFW 旗標。 即使關閉此功能,依伺服器而定也可能會自動設置。"
activeEmailValidationDescription: "強化驗證使用者的電子郵件地址,包含判斷是否為免洗信箱,以及是否可以實際通訊。 停用此選項時,只會檢查是否符合電子郵件地址的形式。"
activeEmailValidationDescription: "積極地驗證用戶的電子郵件地址,判斷它是否為免洗地址,或者它是否可以通信。 若關閉,則只會檢查字元是否正確。"
navbar: "導覽列"
shuffle: "隨機"
account: "帳戶"
@ -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: "檢測敏感度"
@ -918,7 +918,7 @@ _emailUnavailable:
smtp: "郵件伺服器沒有應答"
_ffVisibility:
public: "發佈"
followers: "僅追隨者可見"
followers: "只有關注你的用戶能看到"
private: "私密"
_signup:
almostThere: "即將完成"
@ -1002,7 +1002,7 @@ _mfm:
intro: "MFM是Misskey、Firefish、Akkoma等專用的標記語言可以在各個位置使用。 您可以這裏看到MFM可用語法列表。"
dummy: "Firefish拓展了Fediverse的世界"
mention: "提及"
mentionDescription: "透過 @+使用者名稱 來標示特定使用者。"
mentionDescription: "透過 @+用戶名 來標示特定使用者。"
hashtag: "#tag"
hashtagDescription: "可以使用\"#\"符號後加文字表示話題標籤。"
url: "URL"
@ -1122,7 +1122,7 @@ _wordMute:
muteLangs: 被靜音的語言
muteLangsDescription: OR條件以空格或換行進行分隔。
_instanceMute:
instanceMuteDescription: "將設定的伺服器的所有貼文及轉發靜音。對被靜音伺服器的使用者的回覆也將被靜音。"
instanceMuteDescription: "包括對被靜音伺服器上的用戶的回覆,被設定的伺服器上所有貼文及轉發都會被靜音。"
instanceMuteDescription2: "設定時以換行進行分隔"
title: "被設定的伺服器,貼文將被隱藏。"
heading: "將會被靜音的伺服器"
@ -1236,7 +1236,7 @@ _tutorial:
step5_1: "時間軸,到處都是時間軸!"
step5_2: "您的伺服器已啟用了{timelines}個時間軸。"
step5_3: "首頁 {icon} 時間軸是顯示你追蹤的帳號的貼文。"
step5_4: "本地{icon}時間軸是你可以看到此伺服器上所有使用者的貼文的時間軸。"
step5_4: "本地 {icon} 時間軸是你可以看到伺服器中所有其他用戶的貼文的時間軸。"
step5_5: "社交 {icon} 時間軸是你的 首頁時間軸 和 本地時間軸 的結合體。"
step5_6: "推薦 {icon} 時間軸是顯示你的伺服器管理員推薦的貼文。"
step5_7: "全球 {icon} 時間軸是顯示來自所有其他連接的伺服器的貼文。"
@ -1268,17 +1268,16 @@ _2fa:
renewTOTPOk: 重新配置
step3Title: 輸入驗證碼
securityKeyNotSupported: 您使用的瀏覧器不支援安全金鑰(Security key)。
step2Click: 點擊此二維條碼以註冊2FA至你的安全密鑰或手機的Authenticator應用程式。
_permissions:
"read:account": "查看我的帳戶資訊"
"write:account": "更改我的帳戶資訊"
"read:blocks": "查看封鎖的使用者名單"
"write:blocks": "編輯封鎖的使用者名單"
"read:blocks": "已封鎖用戶名單"
"write:blocks": "編輯已封鎖用戶名單"
"read:drive": "存取雲端硬碟"
"write:drive": "編輯雲端硬碟的檔案"
"read:favorites": "瀏覽我的最愛"
"write:favorites": "編輯我的最愛列表"
"read:following": "查看追隨中的使用者資訊"
"read:following": "查看追隨中的用戶資訊"
"write:following": "追隨/解除追隨"
"read:messaging": "顯示訊息"
"write:messaging": "撰寫或刪除私人訊息"
@ -1344,7 +1343,7 @@ _widgets:
postForm: "發佈窗口"
slideshow: "幻燈片"
button: "按鈕"
onlineUsers: "線上的使用者"
onlineUsers: "線上的用戶"
jobQueue: "佇列"
serverMetric: "伺服器指標"
aiscript: "AiScript 控制台"
@ -1417,14 +1416,14 @@ _profile:
metadataContent: "内容"
changeAvatar: "更換大頭貼"
changeBanner: "變更橫幅圖像"
locationDescription: 如果你先輸入你所在的城市,則會向其他使用者顯示你的當地時間。
locationDescription: 如果你先輸入你所在的城市,則會向其他用戶顯示你的當地時間。
_exportOrImport:
allNotes: "所有貼文"
followingList: "追隨中"
muteList: "靜音"
blockingList: "封鎖"
userLists: "清單"
excludeMutingUsers: "排除被靜音的使用者"
excludeMutingUsers: "排除被靜音的用戶"
excludeInactiveUsers: "排除不活躍帳戶"
_charts:
federation: "站台聯邦"
@ -1827,16 +1826,16 @@ _messaging:
manageGroups: 管理群組
replayTutorial: 重新播放教程
moveFromLabel: '您想遷移的舊帳戶:'
customMOTDDescription: 自訂MOTD(啟動畫面)訊息,一行一個。使用者載入/重新整理頁面時將隨機顯示。
customMOTDDescription: 自訂MOTD(啟動畫面)訊息,一行一個。每次用戶載入/重新整理頁面時將會隨機顯示。
privateModeInfo: 啟用後,只有列入允許名單的伺服器才能與你的伺服器聯合。所有貼文都將對公眾隱藏。
adminCustomCssWarn: 除非你知道它的作用,否則請不要使用此設定。 輸入不正確的值可能會導致每個人的用戶端無法正常運行。你可在你的使用者設定中先行測試,以確保你的
CSS 正常作。
adminCustomCssWarn: 除非你知道它的作用,否則請不要使用此設定。 輸入不正確的值可能會導致每個人的客戶端無法正常運行。你可在你的的用戶設定中測試,確保你的
CSS 正常作。
showUpdates: Firefish 更新時顯示彈出視窗
recommendedInstances: 建議的伺服器
caption: 自動加上替代文字(alt)
enterSendsMessage: 在 Messaging 中按 Return 發送消息 (如關閉則是 Ctrl + Return)
migrationConfirm: "您確定要將你的帳戶遷移到 {account} 嗎? 一旦這樣做,你將無法復原,而你將無法再次正常使用您的帳戶。\n另外請確保你已將此當前帳戶設置為您要遷移的帳戶。"
customSplashIconsDescription: 自訂啟動畫面的圖標網址,一行一個。使用者載入/重新整理頁面時將隨機顯示。請確保圖片位於靜態網址上,最好每個圖片的解析度皆縮放
customSplashIconsDescription: 每次用戶加載/重新加載頁面時,以換行符號分隔的自定啟動畫面圖標的網址將隨機顯示。請確保圖片位於靜態網址上,最好所有圖片解析度調整
192x192。
accountMoved: '該使用者已遷移至新帳戶:'
showAds: 顯示社群橫幅
@ -1874,8 +1873,7 @@ silenced: 已靜音
_experiments:
title: 試驗功能
enablePostImports: 啟用匯入貼文的功能
postImportsCaption:
允許使用者從舊有的Firefish・Misskey・Mastodon・Akkoma・Pleroma帳號匯入貼文。在伺服器佇列堵塞時匯入貼文可能會導致載入速度變慢。
postImportsCaption: 允許用戶從舊有的Firefish・Misskey・Mastodon・Akkoma・Pleroma帳號匯入貼文。在伺服器佇列堵塞時匯入貼文可能會導致載入速度變慢。
findOtherInstance: 找找另一個伺服器
noGraze: 瀏覽器擴充元件 "Graze for Mastodon" 會與Firefish發生衝突請停用該擴充元件。
userSaysSomethingReasonRenote: '{name} 轉發了包含 {reason} 的貼文'
@ -1905,7 +1903,7 @@ newer: 較新
older: 較舊
jumpToPrevious: 跳到上一個
removeReaction: 移除你的反應
listsDesc: 清單可以讓您創建含用指定使用者的時間軸。您可以在時間軸頁面查看它們。
listsDesc: 清單可以創建一個只有您指定用戶的時間軸。 可以從時間軸頁面訪問它們。
flagSpeakAsCatDescription: 在喵咪模式下你的貼文會被喵化ヾ(•ω•`)o
antennasDesc: "天線會顯示符合您設置條件的新貼文!\n 可以從時間軸訪問它們。"
expandOnNoteClick: 點擊以打開貼文
@ -1939,7 +1937,7 @@ isAdmin: 管理員
isPatron: Firefish 項目贊助者
silencedWarning: 顯示此頁面是因為這些使用者來自您伺服器管理員已靜音的伺服器,因此他們可能是垃圾訊息。
signupsDisabled: 此伺服器目前停止註冊,但您隨時可以在另一台伺服器上註冊!如果您有此伺服器的邀請碼,請在下面輸入。
showPopup: 通過彈出式視窗通知使用者
showPopup: 通過彈出式視窗通知用戶
showWithSparkles: 讓標題閃閃發光
youHaveUnreadAnnouncements: 您有未讀的公告
donationLink: 連結到贊助頁面
@ -1948,7 +1946,7 @@ remindMeLater: 可能之後
removeQuote: 删除引用
removeRecipient: 刪除收件者
removeMember: 刪除成員
isBot: 此帳號為自動化帳號
isBot: 此帳戶是機器人
verifiedLink: 已驗證連結
_filters:
followersOnly: 只顯示關注者的
@ -2003,9 +2001,3 @@ _iconSets:
bold: 粗線
duotone: 雙色
light: 細線
showAttachedNotes: 顯示有此附件的貼文
attachedToNotes: 帶有此附件的貼文
useEmojiCdn: 使用CDN的Twemoji
useEmojiCdnDescription: 使用JSDelivr CDN提供的Twemoji而不使用儲存在伺服器上的檔案。
moreUrls: 置頂的頁面
moreUrlsDescription: "請以下列形式輸入欲釘選在左下角幫助選單的頁面,一行一個:\n\"顯示名稱\": https://example.com/"

View File

@ -6,7 +6,7 @@
"type": "git",
"url": "https://git.joinfirefish.org/firefish/firefish.git"
},
"packageManager": "pnpm@8.13.1",
"packageManager": "pnpm@8.10.5",
"private": true,
"scripts": {
"rebuild": "pnpm run clean && pnpm run build",
@ -64,7 +64,7 @@
"gulp-replace": "1.1.4",
"gulp-terser": "2.1.0",
"install-peers": "^1.0.4",
"pnpm": "8.13.1",
"pnpm": "8.10.5",
"start-server-and-test": "2.0.3",
"typescript": "5.2.2"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 889 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

View File

@ -29,7 +29,7 @@
"@bull-board/api": "5.9.1",
"@bull-board/koa": "5.9.1",
"@bull-board/ui": "5.9.1",
"@discordapp/twemoji": "^15.0.2",
"@discordapp/twemoji": "14.1.2",
"@elastic/elasticsearch": "8.10.0",
"@koa/cors": "4.0.0",
"@koa/multer": "3.0.2",
@ -39,7 +39,6 @@
"@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.1",
@ -129,6 +128,7 @@
"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.1",

View File

@ -5,11 +5,11 @@ import Xev from "xev";
import Logger from "@/services/logger.js";
import { envOption } from "../env.js";
import os from "node:os";
// for typeorm
import "reflect-metadata";
import { masterMain } from "./master.js";
import { workerMain } from "./worker.js";
import os from "node:os";
const logger = new Logger("core", "cyan");
const clusterLogger = logger.createSubLogger("cluster", "orange", false);

View File

@ -1,18 +1,18 @@
import * as fs from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
import * as os from "node:os";
import cluster from "node:cluster";
import * as fs from "node:fs";
import * as os from "node:os";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import chalk from "chalk";
import chalkTemplate from "chalk-template";
import semver from "semver";
import Logger from "@/services/logger.js";
import loadConfig from "@/config/load.js";
import type { Config } from "@/config/types.js";
import { db, initDb } from "@/db/postgre.js";
import { envOption } from "@/env.js";
import { showMachineInfo } from "@/misc/show-machine-info.js";
import { db, initDb } from "@/db/postgre.js";
import Logger from "@/services/logger.js";
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);
@ -148,7 +148,9 @@ function showNodejsVersion(): void {
nodejsLogger.info(`Version ${process.version} detected.`);
const minVersion = "v18.16.0";
const minVersion = fs
.readFileSync(`${_dirname}/../../../../.node-version`, "utf-8")
.trim();
if (semver.lt(process.version, minVersion)) {
nodejsLogger.error(`At least Node.js ${minVersion} required!`);
process.exit(1);

View File

@ -1,6 +1,6 @@
import cluster from "node:cluster";
import { initDb } from "@/db/postgre.js";
import os from "node:os";
import { initDb } from "@/db/postgre.js";
/**
* Init worker process

View File

@ -3,10 +3,10 @@
*/
import * as fs from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import * as yaml from "js-yaml";
import type { Source, Mixin } from "./types.js";
import type { Mixin, Source } from "./types.js";
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);

View File

@ -14,8 +14,10 @@ export const MAX_CAPTION_TEXT_LENGTH = Math.min(
);
export const SECOND = 1000;
export const MINUTE = 60 * SECOND;
export const HOUR = 60 * MINUTE;
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 DAY = 24 * HOUR;
export const USER_ONLINE_THRESHOLD = 10 * MINUTE;

View File

@ -1,5 +1,5 @@
import Xev from "xev";
import { deliverQueue, inboxQueue } from "@/queue/queues.js";
import Xev from "xev";
const ev = new Xev();

View File

@ -1,8 +1,8 @@
import meilisearch from "@/db/meilisearch.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
import * as osUtils from "os-utils";
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";
const ev = new Xev();

View File

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

View File

@ -1,9 +1,9 @@
import { Health, Index, MeiliSearch, Stats } from "meilisearch";
import { dbLogger } from "./logger.js";
import * as url from "url";
import config from "@/config/index.js";
import { Note } from "@/models/entities/note.js";
import * as url from "url";
import { ILocalUser } from "@/models/entities/user.js";
import { Followings, Users } from "@/models/index.js";
@ -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 (Number.isNaN(date)) return 0;
if (isNaN(date)) return 0;
unix = date / 1000;
}

View File

@ -2,76 +2,76 @@
import pg from "pg";
pg.types.setTypeParser(20, Number);
import config from "@/config/index.js";
import * as highlight from "cli-highlight";
import type { Logger } from "typeorm";
import { DataSource } from "typeorm";
import * as highlight from "cli-highlight";
import config from "@/config/index.js";
import { User } from "@/models/entities/user.js";
import { DriveFile } from "@/models/entities/drive-file.js";
import { DriveFolder } from "@/models/entities/drive-folder.js";
import { AccessToken } from "@/models/entities/access-token.js";
import { App } from "@/models/entities/app.js";
import { PollVote } from "@/models/entities/poll-vote.js";
import { Note } from "@/models/entities/note.js";
import { NoteReaction } from "@/models/entities/note-reaction.js";
import { NoteWatching } from "@/models/entities/note-watching.js";
import { NoteThreadMuting } from "@/models/entities/note-thread-muting.js";
import { NoteUnread } from "@/models/entities/note-unread.js";
import { Notification } from "@/models/entities/notification.js";
import { Meta } from "@/models/entities/meta.js";
import { Following } from "@/models/entities/following.js";
import { Instance } from "@/models/entities/instance.js";
import { Muting } from "@/models/entities/muting.js";
import { RenoteMuting } from "@/models/entities/renote-muting.js";
import { SwSubscription } from "@/models/entities/sw-subscription.js";
import { Blocking } from "@/models/entities/blocking.js";
import { UserList } from "@/models/entities/user-list.js";
import { UserListJoining } from "@/models/entities/user-list-joining.js";
import { UserGroup } from "@/models/entities/user-group.js";
import { UserGroupJoining } from "@/models/entities/user-group-joining.js";
import { UserGroupInvitation } from "@/models/entities/user-group-invitation.js";
import { Hashtag } from "@/models/entities/hashtag.js";
import { NoteFavorite } from "@/models/entities/note-favorite.js";
import { AbuseUserReport } from "@/models/entities/abuse-user-report.js";
import { RegistrationTicket } from "@/models/entities/registration-tickets.js";
import { MessagingMessage } from "@/models/entities/messaging-message.js";
import { Signin } from "@/models/entities/signin.js";
import { AuthSession } from "@/models/entities/auth-session.js";
import { FollowRequest } from "@/models/entities/follow-request.js";
import { Emoji } from "@/models/entities/emoji.js";
import { UserNotePining } from "@/models/entities/user-note-pining.js";
import { Poll } from "@/models/entities/poll.js";
import { UserKeypair } from "@/models/entities/user-keypair.js";
import { UserPublickey } from "@/models/entities/user-publickey.js";
import { UserProfile } from "@/models/entities/user-profile.js";
import { UserSecurityKey } from "@/models/entities/user-security-key.js";
import { AttestationChallenge } from "@/models/entities/attestation-challenge.js";
import { Page } from "@/models/entities/page.js";
import { PageLike } from "@/models/entities/page-like.js";
import { GalleryPost } from "@/models/entities/gallery-post.js";
import { GalleryLike } from "@/models/entities/gallery-like.js";
import { ModerationLog } from "@/models/entities/moderation-log.js";
import { UsedUsername } from "@/models/entities/used-username.js";
import { Announcement } from "@/models/entities/announcement.js";
import { AccessToken } from "@/models/entities/access-token.js";
import { Ad } from "@/models/entities/ad.js";
import { AnnouncementRead } from "@/models/entities/announcement-read.js";
import { Clip } from "@/models/entities/clip.js";
import { ClipNote } from "@/models/entities/clip-note.js";
import { Announcement } from "@/models/entities/announcement.js";
import { Antenna } from "@/models/entities/antenna.js";
import { PromoNote } from "@/models/entities/promo-note.js";
import { PromoRead } from "@/models/entities/promo-read.js";
import { Relay } from "@/models/entities/relay.js";
import { MutedNote } from "@/models/entities/muted-note.js";
import { Channel } from "@/models/entities/channel.js";
import { App } from "@/models/entities/app.js";
import { AttestationChallenge } from "@/models/entities/attestation-challenge.js";
import { AuthSession } from "@/models/entities/auth-session.js";
import { Blocking } from "@/models/entities/blocking.js";
import { ChannelFollowing } from "@/models/entities/channel-following.js";
import { ChannelNotePining } from "@/models/entities/channel-note-pining.js";
import { RegistryItem } from "@/models/entities/registry-item.js";
import { Ad } from "@/models/entities/ad.js";
import { PasswordResetRequest } from "@/models/entities/password-reset-request.js";
import { UserPending } from "@/models/entities/user-pending.js";
import { Webhook } from "@/models/entities/webhook.js";
import { UserIp } from "@/models/entities/user-ip.js";
import { Channel } from "@/models/entities/channel.js";
import { ClipNote } from "@/models/entities/clip-note.js";
import { Clip } from "@/models/entities/clip.js";
import { DriveFile } from "@/models/entities/drive-file.js";
import { DriveFolder } from "@/models/entities/drive-folder.js";
import { Emoji } from "@/models/entities/emoji.js";
import { FollowRequest } from "@/models/entities/follow-request.js";
import { Following } from "@/models/entities/following.js";
import { GalleryLike } from "@/models/entities/gallery-like.js";
import { GalleryPost } from "@/models/entities/gallery-post.js";
import { Hashtag } from "@/models/entities/hashtag.js";
import { Instance } from "@/models/entities/instance.js";
import { MessagingMessage } from "@/models/entities/messaging-message.js";
import { Meta } from "@/models/entities/meta.js";
import { ModerationLog } from "@/models/entities/moderation-log.js";
import { MutedNote } from "@/models/entities/muted-note.js";
import { Muting } from "@/models/entities/muting.js";
import { NoteEdit } from "@/models/entities/note-edit.js";
import { NoteFavorite } from "@/models/entities/note-favorite.js";
import { NoteReaction } from "@/models/entities/note-reaction.js";
import { NoteThreadMuting } from "@/models/entities/note-thread-muting.js";
import { NoteUnread } from "@/models/entities/note-unread.js";
import { NoteWatching } from "@/models/entities/note-watching.js";
import { Note } from "@/models/entities/note.js";
import { Notification } from "@/models/entities/notification.js";
import { PageLike } from "@/models/entities/page-like.js";
import { Page } from "@/models/entities/page.js";
import { PasswordResetRequest } from "@/models/entities/password-reset-request.js";
import { PollVote } from "@/models/entities/poll-vote.js";
import { Poll } from "@/models/entities/poll.js";
import { PromoNote } from "@/models/entities/promo-note.js";
import { PromoRead } from "@/models/entities/promo-read.js";
import { RegistrationTicket } from "@/models/entities/registration-tickets.js";
import { RegistryItem } from "@/models/entities/registry-item.js";
import { Relay } from "@/models/entities/relay.js";
import { RenoteMuting } from "@/models/entities/renote-muting.js";
import { Signin } from "@/models/entities/signin.js";
import { SwSubscription } from "@/models/entities/sw-subscription.js";
import { UsedUsername } from "@/models/entities/used-username.js";
import { UserGroupInvitation } from "@/models/entities/user-group-invitation.js";
import { UserGroupJoining } from "@/models/entities/user-group-joining.js";
import { UserGroup } from "@/models/entities/user-group.js";
import { UserIp } from "@/models/entities/user-ip.js";
import { UserKeypair } from "@/models/entities/user-keypair.js";
import { UserListJoining } from "@/models/entities/user-list-joining.js";
import { UserList } from "@/models/entities/user-list.js";
import { UserNotePining } from "@/models/entities/user-note-pining.js";
import { UserPending } from "@/models/entities/user-pending.js";
import { UserProfile } from "@/models/entities/user-profile.js";
import { UserPublickey } from "@/models/entities/user-publickey.js";
import { UserSecurityKey } from "@/models/entities/user-security-key.js";
import { User } from "@/models/entities/user.js";
import { Webhook } from "@/models/entities/webhook.js";
import { entities as charts } from "@/services/chart/entities.js";
import { dbLogger } from "./logger.js";

View File

@ -1,5 +1,5 @@
import Redis from "ioredis";
import config from "@/config/index.js";
import Redis from "ioredis";
export function createConnection() {
let source = config.redis;

View File

@ -1,8 +1,8 @@
import config from "@/config/index.js";
import type { IMentionedRemoteUsers } from "@/models/entities/note.js";
import { intersperse } from "@/prelude/array.js";
import { Window } from "happy-dom";
import type * as mfm from "mfm-js";
import config from "@/config/index.js";
import { intersperse } from "@/prelude/array.js";
import type { IMentionedRemoteUsers } from "@/models/entities/note.js";
export function toHtml(
nodes: mfm.MfmNode[] | null,

View File

@ -1,6 +1,6 @@
import { Antennas } from "@/models/index.js";
import type { Antenna } from "@/models/entities/antenna.js";
import { subscriber } from "@/db/redis.js";
import type { Antenna } from "@/models/entities/antenna.js";
import { Antennas } from "@/models/index.js";
let antennasFetched = false;
let antennas: Antenna[] = [];

View File

@ -1,7 +1,5 @@
// https://gist.github.com/nfantone/1eaa803772025df69d07f4dbf5df7e58
"use strict";
/**
* @callback BeforeShutdownListener
* @param {string} [signalOrEvent] The exit signal or event name received on the process.

View File

@ -1,6 +1,6 @@
import { redisClient } from "@/db/redis.js";
import { encode, decode } from "msgpackr";
import { ChainableCommander } from "ioredis";
import { decode, encode } from "msgpackr";
export class Cache<T> {
private ttl: number;

View File

@ -1,7 +1,7 @@
import fetch from "node-fetch";
import { URLSearchParams } from "node:url";
import { getAgentByUrl } from "@/misc/fetch.js";
import config from "@/config/index.js";
import { getAgentByUrl } from "@/misc/fetch.js";
import fetch from "node-fetch";
export async function verifyRecaptcha(secret: string, response: string) {
const result = await getCaptchaResponse(

View File

@ -1,12 +1,12 @@
import * as Acct from "@/misc/acct.js";
import { Cache } from "@/misc/cache.js";
import { getWordHardMute } from "@/misc/check-word-mute.js";
import { getFullApAccount } from "@/misc/convert-host.js";
import type { Packed } from "@/misc/schema.js";
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 "@/misc/convert-host.js";
import * as Acct from "@/misc/acct.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);

View File

@ -1,5 +1,5 @@
import RE2 from "re2";
import type { Note } from "@/models/entities/note.js";
import RE2 from "re2";
type NoteLike = {
userId: Note["userId"];

View File

@ -1,6 +1,6 @@
import { URL } from "node:url";
import config from "@/config/index.js";
import { toASCII } from "punycode";
import config from "@/config/index.js";
export function getFullApAccount(username: string, host: string | null) {
return host

View File

@ -1,5 +1,5 @@
import { detect } from "tinyld";
import * as mfm from "mfm-js";
import { detect } from "tinyld";
export default function detectLanguage(text: string): string {
const nodes = mfm.parse(text);

View File

@ -1,13 +1,13 @@
import * as fs from "node:fs";
import * as stream from "node:stream";
import * as util from "node:util";
import got, * as Got from "got";
import { httpAgent, httpsAgent, StatusError } from "./fetch.js";
import config from "@/config/index.js";
import chalk from "chalk";
import Logger from "@/services/logger.js";
import chalk from "chalk";
import got, * as Got from "got";
import IPCIDR from "ip-cidr";
import PrivateIp from "private-ip";
import { StatusError, httpAgent, httpsAgent } from "./fetch.js";
const pipeline = util.promisify(stream.pipeline);

View File

@ -2,9 +2,9 @@ import probeImageSize from "probe-image-size";
import { Mutex } from "redis-semaphore";
import { FILE_TYPE_BROWSERSAFE } from "@/const.js";
import { redisClient } from "@/db/redis.js";
import Logger from "@/services/logger.js";
import { Cache } from "./cache.js";
import { redisClient } from "@/db/redis.js";
export type Size = {
width: number;

View File

@ -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})`);

View File

@ -1,5 +1,5 @@
import * as mfm from "mfm-js";
import { unique } from "@/prelude/array.js";
import * as mfm from "mfm-js";
export function extractCustomEmojisFromMfm(nodes: mfm.MfmNode[]): string[] {
const emojiNodes = mfm.extract(nodes, (node) => {

View File

@ -1,5 +1,5 @@
import * as mfm from "mfm-js";
import { unique } from "@/prelude/array.js";
import * as mfm from "mfm-js";
export function extractHashtags(nodes: mfm.MfmNode[]): string[] {
const hashtagNodes = mfm.extract(nodes, (node) => node.type === "hashtag");

View File

@ -1,6 +1,6 @@
import { fetchMeta } from "./fetch-meta.js";
import type { ILocalUser } from "@/models/entities/user.js";
import { Users } from "@/models/index.js";
import { fetchMeta } from "./fetch-meta.js";
export async function fetchProxyAccount(): Promise<ILocalUser | null> {
const meta = await fetchMeta();

View File

@ -1,10 +1,10 @@
import * as http from "node:http";
import * as https from "node:https";
import type { URL } from "node:url";
import CacheableLookup from "cacheable-lookup";
import fetch from "node-fetch";
import { HttpProxyAgent, HttpsProxyAgent } from "hpagent";
import config from "@/config/index.js";
import CacheableLookup from "cacheable-lookup";
import { HttpProxyAgent, HttpsProxyAgent } from "hpagent";
import fetch from "node-fetch";
export async function getJson(
url: string,

View File

@ -1,8 +1,8 @@
import config from "@/config/index.js";
import {
nativeCreateId,
nativeInitIdGenerator,
nativeGetTimestamp,
nativeInitIdGenerator,
} from "native-utils/built/index.js";
const length = Math.min(Math.max(config.cuid?.length ?? 16, 16), 24);

View File

@ -1,17 +1,17 @@
import * as fs from "node:fs";
import * as crypto from "node:crypto";
import * as fs from "node:fs";
import { join } from "node:path";
import * as stream from "node:stream";
import * as util from "node:util";
import { detectSensitive } from "@/services/detect-sensitive.js";
import { encode } from "blurhash";
import { FSWatcher } from "chokidar";
import { fileTypeFromFile } from "file-type";
import probeImageSize from "probe-image-size";
import FFmpeg from "fluent-ffmpeg";
import isSvg from "is-svg";
import { type predictionType } from "nsfwjs";
import probeImageSize from "probe-image-size";
import sharp from "sharp";
import { encode } from "blurhash";
import { detectSensitive } from "@/services/detect-sensitive.js";
import { createTempDir } from "./create-temp.js";
const pipeline = util.promisify(stream.pipeline);

View File

@ -1,6 +1,6 @@
import { UserKeypairs } from "@/models/index.js";
import type { User } from "@/models/entities/user.js";
import type { UserKeypair } from "@/models/entities/user-keypair.js";
import type { User } from "@/models/entities/user.js";
import { UserKeypairs } from "@/models/index.js";
import { Cache } from "./cache.js";
const cache = new Cache<UserKeypair>("keypairStore", 60 * 30);

View File

@ -1,5 +1,5 @@
import bcrypt from "bcryptjs";
import * as argon2 from "argon2";
import bcrypt from "bcryptjs";
export async function hashPassword(password: string): Promise<string> {
return argon2.hash(password);

View File

@ -1,13 +1,13 @@
import { In, IsNull } from "typeorm";
import { Emojis } from "@/models/index.js";
import config from "@/config/index.js";
import { redisClient } from "@/db/redis.js";
import type { Emoji } from "@/models/entities/emoji.js";
import type { Note } from "@/models/entities/note.js";
import { Emojis } from "@/models/index.js";
import { query } from "@/prelude/url.js";
import { In, IsNull } from "typeorm";
import { Cache } from "./cache.js";
import { isSelfHost, toPunyNullable } from "./convert-host.js";
import { decodeReaction } from "./reaction-lib.js";
import config from "@/config/index.js";
import { query } from "@/prelude/url.js";
import { redisClient } from "@/db/redis.js";
const cache = new Cache<Emoji | null>("populateEmojis", 60 * 60 * 12);

View File

@ -1,13 +1,13 @@
import * as fs from "node:fs";
import * as Path from "node:path";
import { Users } from "@/models/index.js";
import { addFile } from "@/services/drive/add-file.js";
import Logger from "@/services/logger.js";
import decompress from "decompress";
import gunzip from "gunzip-maybe";
import * as tar from "tar-stream";
import { createTemp, createTempDir } from "./create-temp.js";
import { downloadUrl } from "./download-url.js";
import { addFile } from "@/services/drive/add-file.js";
import { Users } from "@/models/index.js";
import * as tar from "tar-stream";
import gunzip from "gunzip-maybe";
import decompress from "decompress";
import * as Path from "node:path";
const logger = new Logger("process-masto-notes");

View File

@ -1,8 +1,8 @@
import { Emojis } from "@/models/index.js";
import { IsNull } from "typeorm";
import { toPunyNullable } from "./convert-host.js";
import { emojiRegex } from "./emoji-regex.js";
import { fetchMeta } from "./fetch-meta.js";
import { Emojis } from "@/models/index.js";
import { toPunyNullable } from "./convert-host.js";
import { IsNull } from "typeorm";
export function convertReactions(reactions: Record<string, number>) {
const result = new Map();

View File

@ -1,36 +1,36 @@
import {
packedUserLiteSchema,
packedUserDetailedNotMeOnlySchema,
packedMeDetailedOnlySchema,
packedUserDetailedNotMeSchema,
packedMeDetailedSchema,
packedUserDetailedSchema,
packedUserSchema,
} from "@/models/schema/user.js";
import { packedNoteSchema } from "@/models/schema/note.js";
import { packedUserListSchema } from "@/models/schema/user-list.js";
import { packedAntennaSchema } from "@/models/schema/antenna.js";
import { packedAppSchema } from "@/models/schema/app.js";
import { packedMessagingMessageSchema } from "@/models/schema/messaging-message.js";
import { packedNotificationSchema } from "@/models/schema/notification.js";
import { packedBlockingSchema } from "@/models/schema/blocking.js";
import { packedChannelSchema } from "@/models/schema/channel.js";
import { packedClipSchema } from "@/models/schema/clip.js";
import { packedDriveFileSchema } from "@/models/schema/drive-file.js";
import { packedDriveFolderSchema } from "@/models/schema/drive-folder.js";
import { packedFollowingSchema } from "@/models/schema/following.js";
import { packedMutingSchema } from "@/models/schema/muting.js";
import { packedRenoteMutingSchema } from "@/models/schema/renote-muting.js";
import { packedBlockingSchema } from "@/models/schema/blocking.js";
import { packedNoteReactionSchema } from "@/models/schema/note-reaction.js";
import { packedHashtagSchema } from "@/models/schema/hashtag.js";
import { packedPageSchema } from "@/models/schema/page.js";
import { packedUserGroupSchema } from "@/models/schema/user-group.js";
import { packedNoteFavoriteSchema } from "@/models/schema/note-favorite.js";
import { packedChannelSchema } from "@/models/schema/channel.js";
import { packedAntennaSchema } from "@/models/schema/antenna.js";
import { packedClipSchema } from "@/models/schema/clip.js";
import { packedFederationInstanceSchema } from "@/models/schema/federation-instance.js";
import { packedQueueCountSchema } from "@/models/schema/queue.js";
import { packedGalleryPostSchema } from "@/models/schema/gallery-post.js";
import { packedEmojiSchema } from "@/models/schema/emoji.js";
import { packedFederationInstanceSchema } from "@/models/schema/federation-instance.js";
import { packedFollowingSchema } from "@/models/schema/following.js";
import { packedGalleryPostSchema } from "@/models/schema/gallery-post.js";
import { packedHashtagSchema } from "@/models/schema/hashtag.js";
import { packedMessagingMessageSchema } from "@/models/schema/messaging-message.js";
import { packedMutingSchema } from "@/models/schema/muting.js";
import { packedNoteEdit } from "@/models/schema/note-edit.js";
import { packedNoteFavoriteSchema } from "@/models/schema/note-favorite.js";
import { packedNoteReactionSchema } from "@/models/schema/note-reaction.js";
import { packedNoteSchema } from "@/models/schema/note.js";
import { packedNotificationSchema } from "@/models/schema/notification.js";
import { packedPageSchema } from "@/models/schema/page.js";
import { packedQueueCountSchema } from "@/models/schema/queue.js";
import { packedRenoteMutingSchema } from "@/models/schema/renote-muting.js";
import { packedUserGroupSchema } from "@/models/schema/user-group.js";
import { packedUserListSchema } from "@/models/schema/user-list.js";
import {
packedMeDetailedOnlySchema,
packedMeDetailedSchema,
packedUserDetailedNotMeOnlySchema,
packedUserDetailedNotMeSchema,
packedUserDetailedSchema,
packedUserLiteSchema,
packedUserSchema,
} from "@/models/schema/user.js";
export const refs = {
UserLite: packedUserLiteSchema,

View File

@ -1,6 +1,6 @@
import * as os from "node:os";
import sysUtils from "systeminformation";
import type Logger from "@/services/logger.js";
import sysUtils from "systeminformation";
export async function showMachineInfo(parentLogger: Logger) {
const logger = parentLogger.createSubLogger("machine");

View File

@ -1,8 +1,8 @@
import { Brackets } from "typeorm";
import { fetchMeta } from "@/misc/fetch-meta.js";
import { Instances } from "@/models/index.js";
import type { Instance } from "@/models/entities/instance.js";
import { DAY } from "@/const.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
import type { Instance } from "@/models/entities/instance.js";
import { Instances } from "@/models/index.js";
import { Brackets } from "typeorm";
import { shouldBlockInstance } from "./should-block-instance.js";
// Threshold from last contact after which an instance will be considered

View File

@ -1,6 +1,6 @@
import { Webhooks } from "@/models/index.js";
import type { Webhook } from "@/models/entities/webhook.js";
import { subscriber } from "@/db/redis.js";
import type { Webhook } from "@/models/entities/webhook.js";
import { Webhooks } from "@/models/index.js";
let webhooksFetched = false;
let webhooks: Webhook[] = [];

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
export class AbuseUserReport {

View File

@ -1,14 +1,14 @@
import {
Entity,
PrimaryColumn,
Index,
Column,
ManyToOne,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { App } from "./app.js";
import { id } from "../id.js";
import { App } from "./app.js";
import { User } from "./user.js";
@Entity()
export class AccessToken {

View File

@ -1,4 +1,4 @@
import { Entity, Index, Column, PrimaryColumn } from "typeorm";
import { Column, Entity, Index, PrimaryColumn } from "typeorm";
import { id } from "../id.js";
@Entity()

View File

@ -1,14 +1,14 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { Announcement } from "./announcement.js";
import { id } from "../id.js";
import { Announcement } from "./announcement.js";
import { User } from "./user.js";
@Entity()
@Index(["userId", "announcementId"], { unique: true })

View File

@ -1,4 +1,4 @@
import { Entity, Index, Column, PrimaryColumn } from "typeorm";
import { Column, Entity, Index, PrimaryColumn } from "typeorm";
import { id } from "../id.js";
@Entity()

View File

@ -1,15 +1,15 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { UserList } from "./user-list.js";
import { UserGroupJoining } from "./user-group-joining.js";
import { UserList } from "./user-list.js";
import { User } from "./user.js";
@Entity()
export class Antenna {

View File

@ -1,6 +1,6 @@
import { Entity, PrimaryColumn, Column, Index, ManyToOne } from "typeorm";
import { User } from "./user.js";
import { Column, Entity, Index, ManyToOne, PrimaryColumn } from "typeorm";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
export class App {

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Entity,
JoinColumn,
Column,
ManyToOne,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
export class AttestationChallenge {

View File

@ -1,14 +1,14 @@
import {
Entity,
PrimaryColumn,
Index,
Column,
ManyToOne,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { App } from "./app.js";
import { id } from "../id.js";
import { App } from "./app.js";
import { User } from "./user.js";
@Entity()
export class AuthSession {

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
@Index(["blockerId", "blockeeId"], { unique: true })

View File

@ -1,14 +1,14 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { Channel } from "./channel.js";
import { User } from "./user.js";
@Entity()
@Index(["followerId", "followeeId"], { unique: true })

View File

@ -1,14 +1,14 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { Note } from "./note.js";
import { Channel } from "./channel.js";
import { id } from "../id.js";
import { Channel } from "./channel.js";
import { Note } from "./note.js";
@Entity()
@Index(["channelId", "noteId"], { unique: true })

View File

@ -1,14 +1,14 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { DriveFile } from "./drive-file.js";
import { User } from "./user.js";
@Entity()
export class Channel {

View File

@ -1,14 +1,14 @@
import {
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { Note } from "./note.js";
import { Clip } from "./clip.js";
import { id } from "../id.js";
import { Clip } from "./clip.js";
import { Note } from "./note.js";
@Entity()
@Index(["noteId", "clipId"], { unique: true })

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
export class Clip {

View File

@ -1,15 +1,15 @@
import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js";
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { id } from "../id.js";
import { User } from "./user.js";
import { DriveFolder } from "./drive-folder.js";
import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js";
import { User } from "./user.js";
@Entity()
@Index(["userId", "folderId", "id"])

View File

@ -1,13 +1,13 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
Entity,
PrimaryColumn,
Index,
Column,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
export class DriveFolder {

View File

@ -1,4 +1,4 @@
import { PrimaryColumn, Entity, Index, Column } from "typeorm";
import { Column, Entity, Index, PrimaryColumn } from "typeorm";
import { id } from "../id.js";
@Entity()

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
@Index(["followerId", "followeeId"], { unique: true })

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
@Index(["followerId", "followeeId"], { unique: true })

View File

@ -1,14 +1,14 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { GalleryPost } from "./gallery-post.js";
import { User } from "./user.js";
@Entity()
@Index(["userId", "postId"], { unique: true })

View File

@ -1,14 +1,14 @@
import {
Column,
Entity,
Index,
JoinColumn,
Column,
PrimaryColumn,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import type { DriveFile } from "./drive-file.js";
import { User } from "./user.js";
@Entity()
export class GalleryPost {

View File

@ -1,6 +1,6 @@
import { Entity, PrimaryColumn, Index, Column } from "typeorm";
import type { User } from "./user.js";
import { Column, Entity, Index, PrimaryColumn } from "typeorm";
import { id } from "../id.js";
import type { User } from "./user.js";
@Entity()
export class Hashtag {

View File

@ -1,4 +1,4 @@
import { Entity, PrimaryColumn, Index, Column } from "typeorm";
import { Column, Entity, Index, PrimaryColumn } from "typeorm";
import { id } from "../id.js";
@Entity()

View File

@ -1,15 +1,15 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { DriveFile } from "./drive-file.js";
import { id } from "../id.js";
import { DriveFile } from "./drive-file.js";
import { UserGroup } from "./user-group.js";
import { User } from "./user.js";
@Entity()
export class MessagingMessage {

View File

@ -1,7 +1,7 @@
import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from "typeorm";
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from "typeorm";
import { id } from "../id.js";
import { User } from "./user.js";
import type { Clip } from "./clip.js";
import { User } from "./user.js";
@Entity()
export class Meta {

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
export class ModerationLog {

View File

@ -1,15 +1,15 @@
import {
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { mutedNoteReasons } from "../../types.js";
import { id } from "../id.js";
import { Note } from "./note.js";
import { User } from "./user.js";
import { id } from "../id.js";
import { mutedNoteReasons } from "../../types.js";
@Entity()
@Index(["noteId", "userId"], { unique: true })

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
@Index(["muterId", "muteeId"], { unique: true })

View File

@ -1,14 +1,14 @@
import {
Entity,
JoinColumn,
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
Index,
} from "typeorm";
import { Note } from "./note.js";
import { id } from "../id.js";
import { DriveFile } from "./drive-file.js";
import { Note } from "./note.js";
@Entity()
export class NoteEdit {

View File

@ -1,14 +1,14 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { id } from "../id.js";
import { Note } from "./note.js";
import { User } from "./user.js";
import { id } from "../id.js";
@Entity()
@Index(["userId", "noteId"], { unique: true })

View File

@ -1,14 +1,14 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { Note } from "./note.js";
import { id } from "../id.js";
import { Note } from "./note.js";
import { User } from "./user.js";
@Entity()
@Index(["userId", "noteId"], { unique: true })

View File

@ -1,13 +1,13 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { id } from "../id.js";
import { User } from "./user.js";
@Entity()
@Index(["userId", "threadId"], { unique: true })

View File

@ -1,15 +1,15 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { Note } from "./note.js";
import { id } from "../id.js";
import type { Channel } from "./channel.js";
import { Note } from "./note.js";
import { User } from "./user.js";
@Entity()
@Index(["userId", "noteId"], { unique: true })

View File

@ -1,14 +1,14 @@
import {
PrimaryColumn,
Column,
Entity,
Index,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
} from "typeorm";
import { User } from "./user.js";
import { Note } from "./note.js";
import { id } from "../id.js";
import { Note } from "./note.js";
import { User } from "./user.js";
@Entity()
@Index(["userId", "noteId"], { unique: true })

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