> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fivenetwork.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Instalação

> Passo a passo para instalar, adaptar e configurar o Five Livestream no seu servidor FiveM.

## Dependências

<CardGroup cols={2}>
  <Card title="Base Five (vRP)" icon="cube">
    O recurso já vem pré-configurado para a base Five Network (vRP). Toda a integração fica isolada em `server/functions.lua`.
  </Card>

  <Card title="oxmysql" icon="database">
    Obrigatório. O script cria suas próprias tabelas automaticamente no primeiro start (não precisa rodar SQL manual).
  </Card>

  <Card title="five-vehicles" icon="car">
    Opcional. Necessário apenas se você usar recompensas do tipo `VEHICLE`. A entrega usa o export `giveVehicle`.
  </Card>
</CardGroup>

<Info>
  O Five Livestream **não precisa que você rode nada além do resource em si**. A API central de login/streams (que guarda os client secrets de Twitch/Google/Kick/TikTok) já é hospedada pelo Five Network — você só preenche a URL e a chave dessa instalação em `config/server/general.lua`, sem instalar nem hospedar nada próprio.
</Info>

<Info>
  O avatar do jogador vem da própria conta vinculada por OAuth. Sem nenhuma conta vinculada ainda, o painel mostra as iniciais do nome.
</Info>

***

## Instalação do recurso

<Steps>
  <Step title="Copie a pasta do recurso">
    Coloque a pasta `five_livestream` dentro do diretório de recursos do seu servidor.
  </Step>

  <Step title="Configure a API central de login">
    Preencha `LIVESTREAM_API_URL` e `LIVESTREAM_API_KEY` em `config/server/general.lua`. Veja [Configuração](/five-livestream/configuracao).
  </Step>

  <Step title="Adapte o functions.lua (se não usar vRP padrão)">
    O recurso já vem pronto para vRP. Para outro framework, veja a seção [Adaptação de framework](#adaptação-de-framework) abaixo.
  </Step>

  <Step title="Configure o restante">
    Jogo/categoria exigida, tag do título, cores e comandos. Veja [Configuração](/five-livestream/configuracao).
  </Step>

  <Step title="Adicione à server.cfg">
    Inicie o recurso depois do vrp (e do five-vehicles, se for usar recompensas de veículo).

    ```text theme={null}
    ensure vrp
    ensure five-vehicles   # opcional, só pra recompensas de veículo
    ensure five_livestream
    ```
  </Step>
</Steps>

<Note>
  O banco de dados (6 tabelas: canais, tempo por jogador, metas, resgates, ranking, temporada) é criado **automaticamente** pelo próprio script ao iniciar. Numa instalação nova (tabelas vazias), o script também já cadastra 5 metas de exemplo (1h a 20h, em gemas) e premiação para as 3 primeiras posições do ranking — só pra não começar com o painel completamente vazio. Edite ou apague pelo próprio painel de admin quando quiser.
</Note>

***

## Adaptação de framework

Toda a comunicação com o framework está isolada em `server/functions.lua`. Nem `server/server.lua` nem `client/client.lua` chamam `vRP.XXX(...)` ou `exports[...]` de outro resource diretamente. Sempre passam por um export deste arquivo. O arquivo já vem implementado para vRP; para outro framework ou fork, reescreva as funções mantendo o **nome** e o **retorno** esperado.

<AccordionGroup>
  <Accordion title="Identidade e permissão do jogador" icon="user">
    ```lua theme={null}
    exports("getUserId", function(source)
        if LoadFiveFramework() then
            return (vRP.getUserId and vRP.getUserId(source)) or (vRP.Passport and vRP.Passport(source))
        end
        return nil
    end)

    exports("hasPermission", function(user_id, permission)
        if LoadFiveFramework() then
            return (vRP.hasPermission and vRP.hasPermission(user_id, permission))
                or (vRP.HasPermission and vRP.HasPermission(user_id, permission))
                or (vRP.hasGroup and vRP.hasGroup(user_id, permission))
                or false
        end
        return false
    end)

    exports("getIdentity", function(user_id)
        if LoadFiveFramework() then
            local identity = (vRP.Identity and vRP.Identity(user_id)) or (vRP.getIdentity and vRP.getIdentity(user_id))
            if not identity then return nil end
            return { name = identity.Name or identity.name, lastname = identity.Lastname or identity.lastname }
        end
        return nil
    end)
    ```

    <Tip>
      Em outros frameworks, `getUserId` deve retornar o identificador **permanente** do jogador (`identifier` no ESX, `citizenid` no QBCore): é essa chave que fica salva nas tabelas do script, não o `source`.
    </Tip>
  </Accordion>

  <Accordion title="Entrega de recompensas" icon="gift">
    ```lua theme={null}
    exports("giveItem", function(user_id, item, amount)
        if LoadFiveFramework() then
            if vRP.GenerateItem then vRP.GenerateItem(user_id, item, amount, true) end
        end
    end)

    -- Via export oficial do resource "five-vehicles" (não é vRP). Retorna {ok=true, plate=...}
    -- ou {ok=false, error=...}.
    exports("giveVehicle", function(user_id, vehicle)
        local vehiclesOk, grantResult = pcall(function() return exports["five-vehicles"]:giveVehicle(user_id, vehicle) end)
        if not vehiclesOk or not grantResult then
            return { ok = false, error = "resource 'five-vehicles' indisponível" }
        end
        return grantResult
    end)

    exports("setPermission", function(user_id, group, level)
        if LoadFiveFramework() then
            if vRP.SetPermission then vRP.SetPermission(user_id, group, level) end
        end
    end)
    ```

    <Info>
      Recompensas do tipo `COINS` não passam por `functions.lua`: o crédito de gemas roda direto em `server/server.lua` via `oxmysql` na tabela `accounts` (coluna `Gemstone`), buscando a `license` pelo `getSource`/`getLicense` do adapter. Se o seu banco de contas for diferente, ajuste a função `giveCoins` em `server/server.lua`. Recompensas do tipo `CAIXA` passam pelo mesmo `giveItem` acima, entregando o item `caixa_<rarity>`.
    </Info>
  </Accordion>

  <Accordion title="Catálogo de itens e veículos" icon="grid-2">
    Alimenta o seletor visual de recompensa no painel de admin (foto + nome, com busca e paginação).

    ```lua theme={null}
    -- Retorna a tabela crua de exports.vrp:ItemList() (chave = Index do item, valor = {Name,...})
    exports("getItemCatalog", function()
        local vrpOk, itemList = pcall(function() return exports.vrp:ItemList() end)
        return (vrpOk and itemList) or {}
    end)

    -- Mesmo motivo, pro catálogo de veículos do "five-vehicles"
    exports("getVehicleCatalog", function()
        local vehiclesOk, vehicleList = pcall(function() return exports["five-vehicles"]:getVehicleList() end)
        return (vehiclesOk and vehicleList) or {}
    end)
    ```

    <Note>
      Se `five-vehicles` não estiver instalado, `getVehicleCatalog` devolve uma lista vazia e o seletor de veículos simplesmente fica sem opções. O resto do painel continua funcionando normalmente.
    </Note>
  </Accordion>
</AccordionGroup>

***

## Performance (StateBags)

Em vez da NUI ficar perguntando pro servidor de tempos em tempos, o servidor empurra atualização só quando o dado muda de verdade, usando statebags do FiveM:

* `livestream_liveStreams` (global): lista de "ao vivo agora", atualizada a cada checagem de Twitch/Kick/YouTube.
* `livestream_analytics` (por jogador): tempo total do jogador, atualizado na hora em que ele ganha ou perde tempo. O painel reflete sem esperar o próximo ciclo automático.

***

## Limitações conhecidas

<AccordionGroup>
  <Accordion title="TikTok não tem checagem automática de live" icon="triangle-exclamation">
    O login/vínculo de conta é OAuth como as demais; só a detecção automática de live ainda não cobre essa plataforma, então não é possível creditar tempo automaticamente para ela.
  </Accordion>

  <Accordion title="Cota da API do YouTube" icon="triangle-exclamation">
    Cada busca de "live agora" custa 100 das 10.000 unidades de cota gratuita diária do Google, por isso o intervalo de checagem do YouTube é bem mais espaçado que Twitch/Kick, e escala mal com muitos canais vinculados simultaneamente.
  </Accordion>
</AccordionGroup>
