The tmc CLI - The Modding Community

Ещё Не Выпущено

tmc — клиент командной строки для нашего публичного API контента. Он создаёт, редактирует и удаляет ваши ассеты, моды, серверы, статьи, сообщества, коллекции и группы — и, поскольку именно ради этого API и используют, он загружает файлы и выпускает релизы одной командой.

Python 3.10+Без зависимостейЛицензия MIT

tmc ещё не выпущен. Его нет на PyPI и у него нет публичного репозитория — сегодня он ставится из копии исходников, и эта страница описывает то, что инструмент уже умеет, а не анонсирует запуск.

install.sh
# From the source checkout — there is nothing to build
pip install .
pip install '.[fast]'   # optional: cryptography, for faster signing
tmc --version       # tmc 1.1.0

# Keys are made under Account → API Keys
tmc auth login --token tmc_xxxxxxxxxxxx
tmc auth whoami

# …or read public items with no key at all
tmc mod list --anon --app 4 -o json

Один пакет на стандартной библиотеке — нечего собирать и нечего разрешать, а каждая команда, флаг и код возврата описаны в документации.

Релизы

Ради Чего Вообще Нужен Инструмент

Выпустить релиз через «сырое» API — это четыре запроса в определённом порядке: загрузить файлы, собрать их идентификаторы, прочитать уже существующий набор релизов и записать новый не задев остальные. release publish — это и есть вся эта последовательность.

publish.sh
# Upload the files, attach them, write the release — one command
tmc release publish --mod 5 \
  --version 1.2.0 \
  --title "Bug fixes" \
  --content-file CHANGELOG.md \
  --file 'dist/*.zip' --file dist/checksums.txt

# Everything on the item, without re-sending the item
tmc release list  --mod 5
tmc release files --mod 5 --version 1.2.0

Повторный Запуск Обновляет

Та же --version во второй раз обновляет этот релиз и добавляет новые файлы в его набор. Остальные ваши релизы не трогаются, а скрытый релиз остаётся скрытым.

Шаблоны, Пакетами

Передайте --file 'dist/*.zip' и сколько угодно файлов; ограничение в двадцать загрузок на запрос обрабатывается за вас.

Большие Файлы Передаются Потоком

Загрузка в 1 ГБ читается с диска кусками, а не целиком в память. Всё, что превышает лимит размера для вашего ключа, отмечается до отправки.
Что Он Умеет

Всё, Что Умеет API, Разложено По Полочкам

По одной команде на каждое действие, которое вы сделали бы в браузере, и на несколько таких, которые в браузере делать не захочется: массовые правки, конвейеры и релизы по скрипту.

Вообще Никаких Зависимостей

Python 3.10+ и стандартная библиотека. Положите его на сборочную машину или игровой сервер без индекса пакетов — и он работает. Для подписи используется cryptography, если она случайно установлена, и встроенная реализация RFC 8032, если нет — подписи в обоих случаях одинаковы.

Оба Режима Аутентификации

Ключи Bearer tmc_ либо подписанные утверждения Ed25519, где закрытый ключ остаётся у вас, а мы храним только публичную половину.

Одна Грамматика Для Каждого Типа

Одни и те же пять глаголов — list, get, create, update, delete — для всех четырнадцати типов, двенадцать из которых имеют собственную команду. tmc content <тип> — единообразная форма и единственный путь к самостоятельным типам release и media.

Связи Без Повторной Отправки

Теги, медиа, релизы, ссылки, источники и элементы коллекций управляются отдельно, так что добавить один скриншот — не значит переписывать весь объект.

Массово, В Пределах Каждого Лимита

Создавайте или редактируйте из JSON-файла любой длины. Каждое серверное ограничение — 25 на запись, 100 на удаление, 200 участников связи, 500 ключей при удалении связи, 20 частей загрузки — разбивается на пакеты за вас, а при частичной ошибке называется именно тот элемент, который не прошёл, чтобы можно было продолжить, а не начинать заново.

Опечатки Ловятся Локально

Имена полей сверяются с локальной копией схем API, с подсказкой ближайшего совпадения: у «mod» нет поля «tgs». Возможно, вы имели в виду «tags»? tmc schema mod печатает тот список полей, с которым идёт сверка.

Сделано Для Конвейеров

Семь форматов вывода — table, json, jsonl, csv, tsv, yaml, ids — и --field, чтобы оставить только нужные столбцы. Данные в stdout, прогресс в stderr, и tmc completion bash|zsh|fish для вашей оболочки.

Ограничения Скорости Обрабатываются

Ответ 429 ожидается ровно столько, сколько просит API, но не дольше --retry-wait-max, после чего вам сообщают, сколько осталось, вместо того чтобы подвесить сборку. Повторы применяются только к идемпотентным методам — POST никогда не повторяется молча.
Учётные Данные

Ключи, Профили И Публичная Половина

Войдите один раз, и учётные данные сохранятся в ~/.config/tmc/config.json с правами 0600 — или передайте их через окружение, и диск вообще не будет затронут. По одному профилю на сайт или на ключ, и --anon для той половины API, которой ключ не нужен вовсе.

auth.sh
# A bearer key, or an Ed25519 key you hold the private half of
tmc auth login --token tmc_xxxxxxxxxxxx
tmc auth login --jwt --key-id tmcak_xxxxxxxx --private-key ~/keys/tmc.pem

# A second key on the same site — a scoped one for scripts
tmc auth login --profile ci \
  --base-url https://moddingcommunity.com --token tmc_…
tmc auth use ci

# Which key is active, and what the server lets it do
tmc auth whoami
tmc auth doctor

# …or no key at all
tmc mod list --anon --app 4 -o json

Профиль На Сайт Или На Ключ

--profile указывает нужный, tmc auth use меняет профиль по умолчанию, и у каждого сохранённого значения есть двойник в окружении — TMC_TOKEN, TMC_KEY_ID, TMC_PRIVATE_KEY_FILE, TMC_BASE_URL, TMC_PROFILE.

Узнать, Что Ключ Действительно Может

auth whoami выясняет реальные права ключа тремя намеренно безобидными пробами — чтением, созданием, которое не может пройти валидацию, и удалением пустого списка идентификаторов. Ничего не создаётся и не удаляется; --read-only отправляет только чтение.

Диагностика Настройки

auth doctor сообщает, какой бэкенд подписи используется, безопасны ли права вашего конфигурационного файла и отвечает ли сайт вообще — три вещи, которые стоит знать до отладки конвейера.

Чтение Вообще Без Ключа

--anon читает публичную сводку по семи типам без заголовка Authorization — это действительно другой эндпоинт, поэтому он отклоняет запись ещё до отправки запроса, отбрасывает фильтры, которых у этой поверхности нет, вместо того чтобы делать вид, будто они сработали, и никогда не переключается тихо на сохранённый ключ. --set apiPublic=false — способ вывести объект оттуда.
Связи

Четыре Глагола, Которые Говорят, Что Делают

Опасный — set: в этом API PUT к связи означает «теперь это полный набор», поэтому PUT с одним участником удаляет у объекта всё остальное. CLI держит все четыре раздельно и предупреждает перед отправкой разрушительного.

Команда Метод Значение
tmc rel add POST Добавить эти, остальное не трогать
tmc rel set PUT Теперь это полный набор
tmc rel rm DELETE Убрать названные
tmc rel clear DELETE Убрать все
relations.sh
# Add two tags. The rest of the item is untouched
tmc tags add mod 5 pvp vanilla

# Upload a screenshot and attach it in one step
tmc media add mod 5 --file shot.png --title Screenshot

# Read one relation back
tmc rel get mod 5 releases

# …and the one that REPLACES the whole gallery
tmc rel set mod 5 media --from-file gallery.json
Автоматизация

Создан Жить В CI

Собирайте проект, выпускайте релиз и загружайте его файлы при каждом теге. Учётные данные берутся из окружения, поэтому на раннере ничего не пишется на диск.

release.yml
- name: Publish to TMC
  env:
    TMC_TOKEN: ${{ secrets.TMC_TOKEN }}
  run: |
    tmc release publish --mod 42 \
      --version "${GITHUB_REF_NAME#v}" \
      --content-file CHANGELOG.md \
      --file 'dist/*.zip'

# Clean pipes: data on stdout, progress on stderr
tmc mod list --mine --all -o ids | xargs -n1 tmc mod get -o json

На Раннер Ничего Не Пишется

Учётные данные приходят из окружения, поэтому профиль не создаётся и ничто не переживает задачу. Ключ JWT может остаться секретным файлом, который монтирует раннер, — мы храним только его публичную половину.

Осмысленные Коды Возврата

2 — использование, 3 — аутентификация, 4 — не найдено, 5 — валидация, 6 — превышен лимит, 7 — сервер, 8 — сеть, чтобы конвейер отличал «повторить» от «почини свой ключ».

Устаревшая Сборка Не Заблокирует

Поле, о котором инструмент ещё не знает, всё равно пройдёт с --allow-unknown-fields, а tmc raw отправит вообще любой запрос.

Проверено На Настоящем

75 тестов гоняют настоящий CLI против внутрипроцессного макета API через реальный сокет — оба режима аутентификации, разбиение на пакеты, семантику связей и путь повторных попыток.

Ключи Живут В Аккаунт → Ключи API

Ключ бесплатен, создаётся за секунду и несёт права на чтение / запись / удаление, срок действия, списки разрешённых IP и собственный лимит частоты — так что ключ, отданный сборочному серверу, сможет делать ровно одно. Каждая команда, флаг и код возврата описаны в документации.

Ключ полезен уже сегодня — API работает, документация написана. Сам tmc по-прежнему не выпущен: пакета на PyPI и публичного репозитория пока нет, так что до тех пор это копия исходников.