How do I find the appid for a non-steam game on Steam

Solution 1:

Steam uses two different ids used to load art for non-steam shortcuts.

You can ignore the Big Picture specific logic and set the icon as your desired Big Picture art but that icon will also be used in Steam desktop client.

Steam Desktop

steamgrid figured out how to get a normal shortcut id. They describe the solution as "crc32(exe + appname) + "02000000", using IEEE standard polynomials" and using exe and appname from shortcuts.vdf.

For some reason, steamgrid refers it as the LegacyID, but this is the format for art for steam's redesigned client. This id seems to be unrelated to the desktop shortcut id (which is also used in screenshots.vdf) and unrelated to images in Big Picture mode (which uses the icon field in shortcuts.vdf).

UWPHook as a C# implementation to find the id and separate code for the paths.

import binascii

def get_steam_shortcut_id(exe, appname):
    """Get id for non-steam shortcut.

    get_steam_shortcut_id(str, str) -> int
    """
    grid = Path(f"{steam_path}/userdata/{steamid}/config/grid")
    unique_id = ''.join([exe, appname])
    id_int = binascii.crc32(str.encode(unique_id)) | 0x80000000
    return id_int

Big Picture

scottrice/Ice steamgrid figured out how to get a Big Picture shortcut id. They explain:

Calculates the filename for a given shortcut. This filename is a 64bit integer, where the first 32bits are a CRC32 based off of the name and target (with the added condition that the first bit is always high), and the last 32bits are 0x02000000.

The implementation looks roughly like this (requires pycrc):

# Copyright (c) 2012-2013, 2013 Scott Rice
# All rights reserved. MIT License
import pycrc.algorithms as crc
def get_bigpicture_shortcut_id(exe, appname):
    algorithm = crc.Crc(width = 32, poly = 0x04C11DB7, reflect_in = True, xor_in = 0xffffffff, reflect_out = True, xor_out = 0xffffffff)
    input_string = ''.join([exe,appname])
    top_32 = algorithm.bit_by_bit(input_string) | 0x80000000
    full_64 = (top_32 << 32) | 0x02000000
    return str(full_64)

See the original for more details/comments.

You can see that this is very similar to the normal shortcut id except it has some extra lower bits.

Bringing it Together

We can put it all together to get the locations for all the art like so:

from pathlib import Path
import binascii

def get_steam_shortcut_id(exe, appname):
    """Get id for non-steam shortcut.

    get_steam_shortcut_id(str, str) -> str
    """
    unique_id = ''.join([exe, appname])
    id_int = binascii.crc32(str.encode(unique_id)) | 0x80000000
    return id_int


def get_grid_art_destinations(steam_path, steamid, exe, appname):
    """Get filepaths for the grid images for the input shortcut.

    get_grid_art_destinations(str, str, str, str) -> dict[str,Path]
    """
    grid = Path(f"{steam_path}/userdata/{steamid}/config/grid")
    shortcut = get_steam_shortcut_id(exe, appname)
    bp_shortcut = (shortcut << 32) | 0x02000000
    return {
        'boxart': grid / f"{shortcut}p.jpg",
        'hero':   grid / f"{shortcut}_hero.jpg",
        'logo':   grid / f"{shortcut}_logo.png",
        '10foot': grid / f"{bp_shortcut}.png",
    }

import pprint
pprint.pprint(get_grid_art_destinations("C:/Program Files (x86)/Steam", '00000000', 'c:\\libraries\\itch\\baba\\Baba Is You\\Baba Is You.exe','Baba Is You'))

Here's a complete python implementation.