compose para calls
Some checks failed
Main Deploy Workflow / deploy_web (push) Has been cancelled
Main Deploy Workflow / deploy_playstore_internal (push) Has been cancelled

This commit is contained in:
2026-09-14 15:00:45 -03:00
parent b17c22321e
commit 8927e80cce
2 changed files with 296 additions and 8 deletions

View File

@@ -0,0 +1,68 @@
# Docker Compose - Matrix RTC (LiveKit SFU + lk-jwt-service) para uso com o TatuChat
# Instalação personalizada (Custom Install) no CasaOS.
#
# Pré-requisitos / passos depois de subir:
# 1) NPM (Nginx Proxy Manager) - criar 2 hosts novos:
# - lk.weltonmoura.com.br -> http://<IP_DO_CASAOS>:7880 (ativar "Websockets Support")
# - rtc.weltonmoura.com.br -> http://<IP_DO_CASAOS>:8081
# <IP_DO_CASAOS> = IP LAN exibido nas configurações do CasaOS (ou tente 172.17.0.1).
# 2) No host que já existe no NPM (matrix.weltonmoura.com.br, proxy do Dendrite),
# adicionar no campo "Advanced" o bloco do /.well-known/matrix/client (ver instruções).
# 3) Firewall/port forward: liberar 7881/tcp, 7882/udp e 50100-50200/udp (mídia direta).
#
# IMPORTANTE: substitua <LIVEKIT_KEY> e <LIVEKIT_SECRET> por valores fortes
# (ex.: chave ~20 chars, segredo ~64 chars).
# Ajuste LIVEKIT_FULL_ACCESS_HOMESERVERS para o mesmo "server_name" do seu dendrite.yaml.
#
# Fonte da configuração: https://docs.livekit.io/ | github.com/element-hq/lk-jwt-service
services:
livekit:
container_name: matrix-rtc-livekit
image: livekit/livekit-server:latest
restart: unless-stopped
ports:
- "7880:7880/tcp" # API + WebSocket (usado pelo NPM em lk.weltonmoura.com.br)
- "7881:7881/tcp" # RTC over TCP (fallback de sinalização para clientes)
- "7882:7882/udp" # RTC UDP inicial (contato direto com clientes)
- "50100-50200:50100-50200/udp" # faixa de mídia WebRTC
environment:
LIVEKIT_CONFIG: |-
port: 7880
rtc:
tcp_port: 7881
udp_port: 7882
port_range_start: 50100
port_range_end: 50200
# use_external_ip busca a IP pública via STUN (ideal p/ VPS atrás de 1:1 NAT).
# Se a IP pública estiver direto na interface, troque por:
# use_external_ip: false
# node_ip: "SEU_IP_PUBLICO"
use_external_ip: true
room:
# Sem auto_create: o lk-jwt-service cria as salas só p/ usuários full-access
auto_create: false
keys:
<LIVEKIT_KEY>: <LIVEKIT_SECRET>
healthcheck:
test: [ "CMD", "livekit-server", "healthcheck", "get-health" ]
interval: 30s
timeout: 5s
retries: 3
lk-jwt-service:
container_name: matrix-rtc-jwt
image: ghcr.io/element-hq/lk-jwt-service:latest
restart: unless-stopped
ports:
- "8081:8081" # alcançado pelo NPM em rtc.weltonmoura.com.br
environment:
- LIVEKIT_JWT_BIND=:8081
# URL pública (wss) do LiveKit, exposta pelo NPM em lk.weltonmoura.com.br
- LIVEKIT_URL=wss://lk.weltonmoura.com.br
- LIVEKIT_KEY=<LIVEKIT_KEY>
- LIVEKIT_SECRET=<LIVEKIT_SECRET>
# Server name do seu Dendrite (dendrite.yaml -> global.server_name).
# Se usou matrix.weltonmoura.com.br como server_name, troque aqui.
- LIVEKIT_FULL_ACCESS_HOMESERVERS=weltonmoura.com.br
- LIVEKIT_LOG_LEVEL=info

View File

@@ -43,7 +43,7 @@
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
}, },
"alias": "cognome", "alias": "Apelido",
"@alias": { "@alias": {
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
@@ -813,7 +813,7 @@
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
}, },
"inviteText": "{username} convidou você para o FluffyChat.\n1. Visite fluffychat.im e instale o aplicativo\n2. Entre ou crie uma conta\n3. Abra o link do convite:\n{link}", "inviteText": "{username} convidou você para o TatuChat.\n1. Visite tatuchat.com.br e instale o aplicativo\n2. Entre ou crie uma conta\n3. Abra o link do convite:\n{link}",
"@inviteText": { "@inviteText": {
"type": "String", "type": "String",
"placeholders": { "placeholders": {
@@ -970,7 +970,7 @@
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
}, },
"newMessageInFluffyChat": "💬 Nova mensagem no FluffyChat", "newMessageInFluffyChat": "💬 Nova mensagem no TatuChat",
"@newMessageInFluffyChat": { "@newMessageInFluffyChat": {
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
@@ -1005,7 +1005,7 @@
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
}, },
"noGoogleServicesWarning": "O Firebase Cloud Messaging não parece estar disponível no seu dispositivo. Para receber notificações push, recomendados que você instwl3 o ntfy. Com o ntfy outro provedor do UnifiedPush, você pode receber notificações push de um modo seguro em relação aos dados. Você pode baixar o ntfy da Play Store ou do F-Droid.", "noGoogleServicesWarning": "O Firebase Cloud Messaging não parece estar disponível no seu dispositivo. Para continuar a receber notificações push, recomendamos instalar o ntfy. Com o ntfy ou outro provedor do UnifiedPush, você pode receber notificações push de forma segura e sem abrir mão dos seus dados. Você pode baixar o ntfy pela Play Store ou pelo F-Droid.",
"@noGoogleServicesWarning": { "@noGoogleServicesWarning": {
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
@@ -1131,7 +1131,7 @@
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
}, },
"pleaseChooseAPasscode": "Escolha um código", "pleaseChooseAPasscode": "Escolha um PIN",
"@pleaseChooseAPasscode": { "@pleaseChooseAPasscode": {
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
@@ -1455,7 +1455,7 @@
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
}, },
"tooManyRequestsWarning": "Demasiadas requisições. Por favor, tente novamente mais tarde!", "tooManyRequestsWarning": "Muitas requisições. Tente novamente mais tarde!",
"@tooManyRequestsWarning": { "@tooManyRequestsWarning": {
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
@@ -1933,7 +1933,7 @@
} }
}, },
"openLinkInBrowser": "Abrir link no navegador", "openLinkInBrowser": "Abrir link no navegador",
"disableEncryptionWarning": "Por razões de segurança, não é possível desativar a criptografada uma vez ativada.", "disableEncryptionWarning": "Por razões de segurança, não é possível desativar a criptografia depois que ela é ativada.",
"wrongPinEntered": "PIN incorreto! Tente novamente em {seconds} segundos...", "wrongPinEntered": "PIN incorreto! Tente novamente em {seconds} segundos...",
"@wrongPinEntered": { "@wrongPinEntered": {
"type": "String", "type": "String",
@@ -2470,9 +2470,11 @@
} }
} }
}, },
"mute": "Silenciar",
"@mute": { "@mute": {
"description": "This should be a very short string because there is not much space in the button!" "description": "This should be a very short string because there is not much space in the button!"
}, },
"chatSearchedUntil": "Conversa pesquisada até {time}",
"@chatSearchedUntil": { "@chatSearchedUntil": {
"type": "String", "type": "String",
"placeholders": { "placeholders": {
@@ -2566,5 +2568,223 @@
"type": "String", "type": "String",
"placeholders": {} "placeholders": {}
}, },
"areYouSureDeletePost": "Apagar" "areYouSureDeletePost": "Apagar",
"accountsAndSettings": "Contas e configurações",
"addTag": "Adicionar etiqueta",
"advancedConfigs": "Configurações avançadas",
"advancedConfigurations": "Configurações avançadas",
"appDescription": "Comunique-se com criptografia na rede descentralizada [matrix], de forma simples e acessível para todos.",
"appSubtitle": "Um app de comunicação seguro",
"baseUrl": "URL base",
"biometricsDescription": "Com a autenticação biométrica, você pode desbloquear o app com seu rosto ou sua impressão digital. Os recursos dependem do seu dispositivo.",
"buildDoesNotSupportFirebase": "Esta versão não suporta o Firebase Cloud Messaging.",
"callBack": "Ligar de volta",
"clear": "Limpar",
"clientWellKnownInformation": "Informações do cliente well-known:",
"compressingVideo": "Comprimindo vídeo...",
"couldNotBeSent": "Não foi possível enviar",
"countActiveCallMembers": "{count} pessoas na chamada",
"@countActiveCallMembers": {
"type": "String",
"placeholders": {
"count": {
"type": "int"
}
}
},
"countUnverifiedDevices": "{count, plural, =1{1 dispositivo não verificado na conversa.} other{{count} dispositivos não verificados na conversa.}}",
"@countUnverifiedDevices": {
"type": "int",
"placeholders": {
"count": {
"type": "int"
}
}
},
"createNewAccount": "Criar nova conta",
"createNewChat": "Criar nova conversa",
"createNewTag": "Criar nova etiqueta",
"crop": "Cortar",
"decline": "Recusar",
"deviceIdentityKey": "Chave de identidade do dispositivo",
"disableAppLock": "Desativar bloqueio do app",
"disableAppLockAreYouSure": "Tem certeza que deseja desativar o bloqueio do app?",
"disableBiometrics": "Desativar autenticação biométrica",
"discardEdits": "Você tem alterações que ainda não foram salvas. Descartar as alterações?",
"doubleTapReaction": "Reação com toque duplo",
"doubleTapToReact": "Toque duas vezes para reagir",
"doubleTapToReactDescription": "Toque duas vezes em uma mensagem para reagir em vez de selecionar o texto.",
"draw": "Desenhar",
"editImage": "Editar imagem",
"edited": "(editado)",
"enableBiometrics": "Ativar autenticação biométrica",
"encryptedMessage": "Mensagem criptografada",
"encrypting": "Criptografando",
"enterCall": "Entrar na chamada",
"eraser": "Borracha",
"federationBaseUrl": "URL base de federação",
"forwardCountMessages": "Encaminhar {count, plural, =1{uma mensagem} other{{count} mensagens}}?",
"@forwardCountMessages": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"generatingThumbnail": "Gerando miniatura",
"hangUp": "Encerrar chamada",
"hideRoomsInSpaces": "Ocultar conversas que estão em um espaço",
"identityServer": "Servidor de identidade:",
"incomingCall": "Chamada recebida",
"incomingCallFrom": "Chamada recebida de {user}",
"@incomingCallFrom": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"interactiveVerification": "Verificação interativa",
"interactiveVerificationDescription": "Se você estiver perto da outra pessoa ou se comunicar por um canal seguro, pode verificar todos os dispositivos de uma vez comparando um código de segurança ou emojis.",
"join": "Entrar",
"knownSince": "Conhecido desde: {date}",
"@knownSince": {
"type": "String",
"placeholders": {
"date": {
"type": "String"
}
}
},
"loadingMessages": "Carregando mensagens...",
"logs": "Registros",
"makeAdmin": "Tornar administrador",
"makeModerator": "Tornar moderador",
"matrixId": "ID Matrix",
"messageCanOnlyBeReadByUser": "Sua mensagem tem criptografia de ponta a ponta e só pode ser lida por este usuário:",
"messageCanOnlyBeReadByUsers": "Sua mensagem tem criptografia de ponta a ponta e só pode ser lida por estes usuários:",
"messageNotDecryptable": "Mensagem não descriptografável",
"mirror": "Espelhar",
"missedCall": "Chamada perdida",
"newPassphrase": "Nova frase secreta",
"newPassphraseDescription": "O TatuChat usa criptografia de ponta a ponta. Para não perder suas mensagens, escolha uma frase secreta forte para proteger sua identidade criptográfica e o backup das mensagens criptografadas.",
"noCurve25519KeyFound": "Nenhuma chave curve25519 encontrada",
"noDevicesFound": "Nenhum dispositivo encontrado",
"noKeysTransmitted": "Nenhuma chave transmitida. Tente novamente.",
"noMoreResultsFound": "Nenhum outro resultado encontrado",
"noUserKeyFound": "Nenhuma chave de usuário encontrada",
"openFile": "Abrir arquivo",
"owner": "Dono",
"passphraseLengthRequirement": "Pelo menos 12 caracteres.",
"passphraseNumberRequirement": "Contém pelo menos um número.",
"passphraseSpecialCharactersRequirement": "Contém caracteres especiais.",
"passphraseUpperAndLowerCaseRequirement": "Contém letras maiúsculas e minúsculas.",
"passphrasesMatch": "As frases secretas correspondem",
"playSoundOnNotification": "Reproduzir som nas notificações",
"pleaseEnter6Digits": "Digite 6 dígitos para ativar o bloqueio do app.",
"possibleByYou": "Esta versão só foi possível graças ao seu apoio. O TatuChat continua gratuito, de código aberto e totalmente impulsionado pela comunidade.",
"powerLevel": "Nível de poder",
"preferSpeaker": "Preferir alto-falante",
"publicKey": "Chave pública: {key}",
"@publicKey": {
"type": "String",
"placeholders": {
"key": {
"type": "String"
}
}
},
"raiseHand": "Levantar a mão",
"removeAdminRights": "Remover direitos de administrador",
"removeModeratorRights": "Remover direitos de moderador",
"removeTag": "Remover etiqueta",
"repeatPassphrase": "Repita a frase secreta",
"reset": "Redefinir",
"resetAccount": "Redefinir conta",
"resetAccountWarning": "Ao redefinir sua conta, você perderá para sempre o acesso às suas mensagens antigas. Todos os seus dispositivos atuais precisarão ser verificados novamente. Faça isso apenas quando não houver mais nenhum outro dispositivo para verificar sua sessão e você tiver perdido sua chave de recuperação e sua frase secreta!",
"resetCryptoIdentity": "Redefinir identidade criptográfica",
"resetPin": "Redefinir PIN",
"resetRecoveryKey": "Redefinir chave de recuperação",
"restoreBootstrapDevicesDescription": "Escolha um dos seus outros dispositivos para verificar esta sessão:",
"restoreBootstrapEmptyDevicesDescription": "Digite sua frase secreta ou chave de recuperação para verificar este dispositivo e acessar o backup das suas mensagens criptografadas.",
"restoreCryptoIdentity": "Restaurar identidade criptográfica",
"rotateLeft": "Girar para a esquerda",
"rotateRight": "Girar para a direita",
"save": "Salvar",
"saveAsFile": "Salvar como arquivo",
"searchOrEnterHomeserverAddress": "Pesquisar ou digitar o endereço do servidor",
"selectCamera": "Selecionar câmera",
"selectMicrophone": "Selecionar microfone",
"selectSpeaker": "Selecionar alto-falante",
"sending": "Enviando",
"sendingFilesDoNotExit": "Enviando {count} arquivos... Não saia do app!",
"@sendingFilesDoNotExit": {
"type": "String",
"placeholders": {
"count": {
"type": "int"
}
}
},
"serverRespondedWithError": "O servidor respondeu com uma mensagem de erro: {error}",
"@serverRespondedWithError": {
"type": "String",
"placeholders": {
"error": {
"type": "String"
}
}
},
"setLowPriority": "Definir prioridade baixa",
"setPowerLevel": "Definir nível de poder",
"setPowerLevelDescription": "O nível de poder define o que um membro pode fazer nesta sala e normalmente varia entre 0 e 100.",
"setUpCryptoIdentity": "Configurar identidade criptográfica",
"shareCrashReports": "Compartilhar relatórios de falhas",
"shareCrashReportsDescription": "Compartilhar automaticamente relatórios de falhas com os desenvolvedores?",
"showLess": "Mostrar menos",
"showMore": "Mostrar mais",
"showThumbnailsInTimeline": "Mostrar miniaturas de imagens e vídeos",
"signIn": "Entrar",
"signInGreeting": "Você já tem uma conta no Matrix? Que bom te ver de novo! Escolha seu servidor e entre.",
"signUpGreeting": "O TatuChat é descentralizado! Escolha um servidor para criar sua conta e vamos lá!",
"signedDevice": "Dispositivo assinado",
"startCall": "Iniciar chamada",
"startScreensharing": "Iniciar compartilhamento de tela",
"stopRaiseHand": "Abaixar a mão",
"stopScreensharing": "Parar de compartilhar a tela",
"storeRecoveryKeyDescription": "Anote sua chave de recuperação para poder restaurar suas mensagens criptografadas e sua identidade criptográfica.",
"support": "Suporte",
"supportFluffyChat": "Apoie o TatuChat",
"tagName": "Nome da etiqueta",
"theProcessWasCanceled": "O processo foi cancelado.",
"today": "Hoje",
"toggleCamera": "Alternar câmera",
"toggleMicrophone": "Alternar microfone",
"unableToRegisterDeviceForFirebase": "Não foi possível registrar o dispositivo no Firebase Cloud Messaging.",
"undo": "Desfazer",
"unencryptedMessage": "Mensagem sem criptografia",
"unexpectedErrorOccurded": "Infelizmente, ocorreu um erro inesperado: {msg}",
"@unexpectedErrorOccurded": {
"type": "String",
"placeholders": {
"msg": {
"type": "String"
}
}
},
"unifiedPushDistributors": "Distribuidores do Unified Push:",
"unlock": "Desbloquear",
"unlockWithBiometrics": "Desbloquear com autenticação biométrica",
"unsetLowPriority": "Remover prioridade baixa",
"unsignedDevice": "Dispositivo não assinado",
"uploading": "Enviando arquivo",
"useAppLock": "Usar bloqueio do app",
"videoCall": "Videochamada",
"videoCallsBetaWarning": "As videochamadas são um recurso em teste. Pode haver erros ou comportamentos inesperados. Gostaríamos de ouvir seu feedback.",
"voiceCall": "Chamada de voz",
"waitingForKeys": "Aguardando as chaves... Mantenha o outro dispositivo ativo.",
"waitingForParticipant": "Aguardando participante...",
"yesterday": "Ontem",
"youAreReadyToStart": "Você está pronto para começar!"
} }