Files
obsidian-vault/family/how-to/htpc-steam-nonsteam-shortcuts.md
T

6.6 KiB
Raw Blame History

Non-Steam Shortcuts через VDF

Главное правило

Steam должен быть выключен перед записью shortcuts.vdf. Если Steam работает — он перезапишет файл из памяти при следующем запуске.

Остановка Steam (Bazzite game session)

systemctl --user stop gamescope-session-plus@steam.service
sleep 2
systemctl --user is-active gamescope-session-plus@steam.service  # должен вернуть "inactive"
# правишь VDF
systemctl --user start gamescope-session-plus@steam.service

Если после stop Steam всё ещё активен — повторить.

Процедура (один bash-скрипт)

Один скрипт на HTPC: останавливает Steam → делает бэкап → редактирует VDF → запускает Steam.

Использовать модуль vdf (установлен на HTPC через pip). Никогда не редактировать бинарный VDF через ручную сборку байтов или замену строк — это ломает файл.

#!/bin/bash
set -e

# 1. Остановить Steam
systemctl --user stop gamescope-session-plus@steam.service
sleep 2

# 2. Бэкап
cp ~/.steam/steam/userdata/147839491/config/shortcuts.vdf{,.bak}

# 3. Редактировать VDF (скрипт лежит рядом)
python3 /path/to/edit_vdf.py

# 4. Запустить Steam
systemctl --user start gamescope-session-plus@steam.service

Python-скрипт (edit_vdf.py):

import os, vdf, shutil, binascii, struct

vdf_path = os.path.expanduser('~/.steam/steam/userdata/147839491/config/shortcuts.vdf')

with open(vdf_path, 'rb') as f:
    data = vdf.binary_load(f)

shortcuts = data.get('shortcuts', {})

def compute_appid(name, exe):
    key = exe + name
    top = binascii.crc32(key.encode('utf-8')) | 0x80000000
    return struct.unpack('i', struct.pack('I', top))[0]

next_idx = str(len(shortcuts))
shortcuts[next_idx] = {
    'AppName': 'Game Name',
    'Exe': '/home/bazzite/Emulation/tools/launchers/ryujinx.sh',
    'StartDir': '/home/bazzite/Emulation/tools/launchers',
    'LaunchOptions': '/home/bazzite/Emulation/roms/switch/animal_crossing.nsp',
    'appid': compute_appid('Game Name', '/home/bazzite/Emulation/tools/launchers/ryujinx.sh'),
    'IsHidden': 0,
    'AllowDesktopConfig': 1,
    'AllowOverlay': 1,
    'OpenVR': 0,
    'Devkit': 0,
    'DevkitGameID': '',
    'DevkitOverrideAppID': 0,
    'LastPlayTime': 0,
    'FlatpakAppID': '',
    'sortas': '',
    'tags': {},
}

data['shortcuts'] = shortcuts
with open(vdf_path, 'wb') as f:
    vdf.binary_dump(data, f)

Скрипты на HTPC загружать через scp, не через heredoc.

CompatToolMapping (Proton) в config.vdf

После добавления shortcut нужно прописать Proton в текстовом config.vdf:

import vdf

CONFIG_PATH = os.path.expanduser('~/.local/share/Steam/config/config.vdf')
with open(CONFIG_PATH, 'r') as f:
    config = vdf.load(f)

compat_map = config['InstallConfigStore']['Software']['Valve']['Steam'].setdefault('CompatToolMapping', {})
compat_map[str(appid_signed)] = {
    'name': 'GE-Proton10-34',  # или 'proton_experimental'
    'config': '',
    'Priority': '250',
}

with open(CONFIG_PATH, 'w') as f:
    vdf.dump(config, f)

Полный скилл

Вся процедура (shortcuts + Proton + artwork) описана в скилле steam-emulator-shortcuts. Смотреть там.

Бэкап

cp ~/.steam/steam/userdata/*/config/shortcuts.vdf{,.bak}

Автоматический бэкап shortcuts.vdf делается ежедневно скриптом backup-saves.sh на HTPC, версии хранятся в /run/media/bazzite/Data/backups/saves/shortcuts/ (последние 30 копий).

Перезагрузка Steam

После записи VDF — перезапустить Steam, чтобы он подхватил изменения.

Wide Steam Grid Posters — Порядок действий

Перед остановкой Steam — сначала скачать все постеры. Так как Steam не нужен для скачивания.

Постеры для всех форматов

При добавлении новой не-Steam игры — сразу скачивай все 4 формата:

Размер Формат файла Назначение
920×430 {unsigned_appid}.png Wide — основная карточка в библиотеке
600×900 {unsigned_appid}p.png Poster — вертикальный, при наведении
1920×620 {unsigned_appid}_hero.png Hero — фон на странице игры
1200×351 {unsigned_appid}_logo.png Логотип на hero

Unsigned appid = signed_appid & 0xFFFFFFFF. Пример: -13217200742973247222.

→ Подробно: htpc-steam-nonsteam-shortcuts

Процедура (как делал Whale)

  1. Найти постеры на SteamGridDB — зайти на https://www.steamgriddb.com/game/<ID>, отфильтровать по 920×430.

    • Для новых игр: поискать <игра> site:steamgriddb.com
    • Wide grids часто меньше по количеству чем posters (600×900), их ищем в секции Grids → фильтр Dimensions: 920×430
  2. Получить прямую ссылку CDN — thumbnails на странице grid'a ведут на cdn2.steamgriddb.com/thumb/<hash>.jpg, а полный файл лежит по cdn2.steamgriddb.com/grid/<hash>.png.

  3. Скачать локально:

    curl -s -o /tmp/<appid>.png "https://cdn2.steamgriddb.com/grid/<hash>.png"
    
  4. Закинуть на HTPC через scp в /tmp/:

    scp /tmp/<appid>.png bazzite@192.168.1.86:/tmp/<appid>.png
    
  5. Скопировать в grid-директорию Steam:

    ssh bazzite@192.168.1.86
    cp /tmp/<appid>.png ~/.steam/steam/userdata/147839491/config/grid/<appid>.png
    
  6. Перезапустить Steam (Steam перечитывает grid-файлы свежими при старте, но часто подхватывает и без перезапуска):

    systemctl --user stop gamescope-session-plus@steam.service
    systemctl --user start gamescope-session-plus@steam.service
    

SteamGridDB ключ API

5f0a7cb3366dede2c10860a95795ce60 — для программного доступа.