Agency-Pad Хранилище Медиа
Теперь с AgencyOS27: бесплатное обновление для всех, у кого уже есть планшет.

Где хранятся фото, видео и голосовые сообщения
Каждое фото, видеоклип, запись экрана и голосовое сообщение из Agency Pad сохраняется самим скриптом, начиная с версии 27.1.1. Место хранения выбираете Вы:
| Хранилище | Настройка | Подходит для |
|---|---|---|
| Локальное (по умолчанию) | Не требуется. Работает сразу после установки. | Любых серверов. Файлы остаются на Вашем сервере, в Вашей базе данных. |
| Cloudflare R2 | Около 10 минут, один раз. Бесплатно до 10 ГБ. | Серверов с большим объёмом видео или очень большим числом игроков. |
Fivemanage и Discord больше не используются как хранилище. Вебхуки Discord по-прежнему доступны для логов.
Локальное хранилище (по умолчанию)
Ничего настраивать не нужно. При первом запуске скрипт создаёт в Вашей базе данных две таблицы (agency_media и agency_media_parts) и хранит файлы в них. Нужен только oxmysql, который скрипту в любом случае необходим.
Что это значит для Вас:
- Никакого аккаунта, API-ключа и дополнительного ресурса. Ничего не работает за пределами Вашего сервера.
- Обновления безопасны. Файлы лежат в базе данных, а не в папке ресурса, поэтому замена папки при обновлении сохраняет все фото.
- Резервные копии базы данных включают медиафайлы. База вырастает примерно на треть больше, чем сами файлы. Одно фото занимает около 150 КБ.
- Agency Phone и Agency Pad используют общее хранилище. Фото, сделанное в одном из них, появляется и в другом, включая фото, синхронизированные с Agency Cloud.
- Приложение Agency Companion тоже показывает их на iOS, Android и в веб-версии. Для этого также ничего настраивать не нужно.
Скорость
Файлы передаются через само соединение FiveM, не блокируя игру. FiveM ограничивает скорость, с которой игрок может отправлять данные на сервер (около 165 КБ в секунду), поэтому:
| Что | Сохранение занимает около |
|---|---|
| Фото | 1 секунды |
| Голосовое сообщение | менее 1 секунды |
| Видеоклип на 15 секунд | 20 секунд (камера показывает прогресс в процентах) |
Показ файла другим игрокам происходит быстро, целый клип приходит за несколько секунд. Если на Вашем сервере записывается много видео, Cloudflare R2 сохраняет клипы почти мгновенно.
Настройки в config.lua
AgencyPadConfig.MediaStorage = {
Provider = 'local', -- 'local' или 'cloudflare'
MaxFileMegabytes = 10, -- самый большой отдельный файл (клипы, записи)
TransferKilobytesPerSecond = 1000, -- 'local': с какой скоростью файлы отправляются игрокам
Local = {
RetentionDays = 30, -- удалять файлы старше этого срока (0 = хранить вечно)
MaxStorageGigabytes = 10, -- удалять самые старые файлы сверх этого объёма (0 = без лимита)
},
}
| Параметр | Что делает |
|---|---|
RetentionDays | Файлы старше этого срока автоматически удаляются раз в час. Удалённое фото отображается в галерее небольшой заглушкой. Укажите 0, чтобы хранить всё. |
MaxStorageGigabytes | Когда все файлы вместе превышают этот объём, сначала удаляются самые старые. Укажите 0, чтобы снять ограничение. |
MaxFileMegabytes | Файлы большего размера отклоняются. Также ограничивает видеоклипы и записи экрана. |
TransferKilobytesPerSecond | Скорость на одного игрока при отправке файлов игрокам. У игры всегда приоритет. |
Cloudflare R2, шаг за шагом
Cloudflare R2 бесплатен до 10 ГБ хранилища, 1 миллиона загрузок и 10 миллионов скачиваний в месяц, а скачивания не стоят ничего никогда. При включении R2 Cloudflare запрашивает способ оплаты, даже для бесплатного тарифа. Вы платите только в том случае, если превысите бесплатные лимиты.
1. Включите R2
- Войдите на dash.cloudflare.com (достаточно бесплатного аккаунта).
- В меню слева откройте Storage & databases, затем R2 Object Storage.
- Добавьте подписку R2. В обзоре к оплате сейчас указано $0.00. Примите условия и нажмите Activate.
2. Создайте бакет
- Нажмите Create bucket.
- Задайте имя, например
myserver-media. Позже имя изменить нельзя. - Оставьте расположение Automatic, а класс хранения Standard.
- Нажмите Create bucket.
3. Сделайте файлы доступными для просмотра
- Откройте свой бакет и перейдите в Settings.
- В разделе Public Development URL нажмите Enable, введите
allowи подтвердите. - Скопируйте появившийся адрес, он выглядит как
https://pub-1a2b3c….r2.dev. Это Ваш PublicUrl.
Cloudflare ограничивает адрес r2.dev для очень загруженных серверов. Если у Вас есть собственный домен в Cloudflare, Вы можете добавить его в разделе Custom Domains там же и использовать этот адрес как PublicUrl.
4. Разрешите загрузку из игры
- Оставаясь в Settings, найдите CORS Policy и нажмите Add.
- Удалите всё в текстовом поле, вставьте следующее и нажмите Save:
[
{
"AllowedOrigins": ["https://cfx-nui-agency-phone", "https://cfx-nui-agency-pad"],
"AllowedMethods": ["PUT", "GET"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}
]
Без этого шага игра не сможет загружать файлы, и фото не будут сохраняться. Если Вы переименовали папку ресурса, укажите имя своей папки после cfx-nui-.
5. Создайте ключ
- Вернитесь в R2 Object Storage и нажмите Manage API tokens.
- Нажмите Create API token (подойдёт токен аккаунта).
- Разрешения: Object Read & Write.
- В выборе бакета укажите только Ваш бакет.
- Нажмите Create. Cloudflare показывает Access Key ID и Secret Access Key только один раз, скопируйте оба прямо сейчас.
- Account ID показан в обзоре R2, а также это первая часть S3-адреса (
https://<Account ID>.r2.cloudflarestorage.com).
6. Введите данные в скрипт
Ключи вносятся в config_server.lua. Этот файл читает только сервер, игрокам он никогда не отправляется. Не вносите ключи в config.lua: этот файл отправляется каждому игроку.
-- config_server.lua
AgencyPadServerConfig.Cloudflare = {
AccountId = 'your account id',
Bucket = 'myserver-media',
AccessKeyId = 'your access key id',
SecretAccessKey = 'your secret access key',
PublicUrl = 'https://pub-1a2b3c....r2.dev',
}
Затем укажите провайдера в config.lua и перезапустите ресурс:
AgencyPadConfig.MediaStorage = {
Provider = 'cloudflare',
...
}
Теперь консоль сервера показывает Media: storage: Cloudflare R2, bucket myserver-media. Если чего-то не хватает, консоль сообщит, чего именно, а скрипт продолжит сохранять файлы локально, пока проблема не будет устранена, так что камера никогда не перестаёт работать.
Используете Agency Phone и Agency Pad вместе? Оба могут работать с одним и тем же бакетом и одним и тем же ключом, каждый хранит свои файлы в собственной папке.
Проверьте, что всё работает
Выполните это в консоли сервера (или от имени администратора в игре), указав ID игрока, который находится онлайн:
padmediatest 1
Agency Pad игрока сохраняет небольшое тестовое изображение, загружает его обратно так же, как это сделал бы любой другой игрок, показывает его и воспроизводит короткое голосовое сообщение. Консоль отвечает:
Media test passed for player 1 in 1361 ms: upload ok, download ok, shown as picture ok, app markup and backgrounds ok, voice message plays ok
Добавьте big, чтобы дополнительно проверить видеоклип размером 6 МБ: padmediatest 1 big.
Проблемы и решения
| Что Вы видите | Решение |
|---|---|
could not create the media tables в консоли | oxmysql не запущен или не может подключиться к базе данных. Запустите oxmysql до agency-pad. |
Provider is 'cloudflare', but config_server.lua is missing ... | Одно из пяти значений пусто, или PublicUrl не начинается с https://. Проверьте шаг 6. |
Фото не сохраняются, ошибка Cloudflare HTTP 403 | У ключа нет права записи в этот бакет, или имя бакета указано неверно. Проверьте шаг 5. |
Фото не сохраняются, ошибка Failed to fetch при работе с Cloudflare | Политика CORS из шага 4 отсутствует или в ней указано другое имя ресурса. |
| Сохранённые фото не отображаются при работе с Cloudflare | Public Development URL из шага 3 выключен, или PublicUrl указывает на другой бакет. |
| Видео сохраняется долго | Это нормально для локального хранилища, см. раздел «Скорость» выше. Для мгновенного сохранения клипов используйте Cloudflare R2. |
| Старые фото пропали | Их удалил параметр RetentionDays. Увеличьте значение или укажите 0. |
Переход с Fivemanage или Discord
Переносить ничего не нужно. Ранее сохранённые фото сохраняют свои старые ссылки и остаются видимыми, пока соответствующий сервис продолжает их отдавать. Всё новое попадает в выбранное Вами хранилище. Старые параметры MediaStorageProvider, FiveManageApiUrl, FiveManageApiKey и ScreenshotWebhook игнорируются, и их можно удалить из конфигурации.
Безопасность
- Загружать файлы могут только игроки, подключённые к Вашему серверу. Каждая загрузка предварительно объявляется и проверяется по типу и размеру.
- Содержимое проверяется по первым байтам. Веб-страницу или скрипт невозможно сохранить под видом фото.
- Имена файлов представляют собой 128-битные случайные значения, их нельзя угадать или получить списком.
- Загрузки и скачивания ограничены на каждого игрока.
- В случае Cloudflare каждая загрузка получает собственную ссылку, действительную 5 минут, ровно для одного файла одного типа и одного размера. Секретный ключ никогда не покидает Ваш сервер.