Fix Twitch’s Proprietary Links with Camomile

Twitch has been giving away free games with Twitch Prime for a while now.  But being a streaming service, they didn’t really have a distribution platform in place, at least anything in the same league as Steam or EA Origin, to distribute their games to the eligible masses.  Enter Twitch Desktop, a clunky app that tries to be everything Twitch is along with everything Discord and Steam are, and failing at most of what it tries to do.

When a Twitch Prime member downloads their games through Twitch Desktop, they are written to a special Twitch Games folder and links are added to the desktop and Start menu (on Windows at least) that launch the games.  Unfortunately, they aren’t just ordinary links: these are Twitch Fuel links that open Twitch Desktop, hunt for the game after it loads (which can be hit-or-miss), and THEN tries to load the game.  Fortunately, with a little deobfuscation, guesswork, and magic, we can unmask these links and get things slightly back to normal.

As per my usual format, I’ll explain everything behind the code, then post the code at the end.  Feel free to skip the boring bits if you want: it’s as easy as scrolling down!

What’s a Twitch Fuel Link?

When Twitch generates a link on the desktop, it’s actually a .url file, not a .lnk file.  The URL in the aptly extensioned .url is in the format twitch://fuel-launch/[game id].  Since a .url is essentially a form of .ini file, we can just read this data with Notepad (or similar/better):

[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,0
[InternetShortcut]
URL=twitch://fuel-launch/66cea04c-bedf-4b41-b484-743ba3424657
IDList=
IconFile=C:\Program Files (x86)\Twitch\Games Library\66cea04c-bedf-4b41-b484-743ba3424657\twinspri.exe
IconIndex=0

The most important bits are:

  • URL: the target of the link
  • IconFile: the file that contains the icon for the link
  • IconIndex: the index of the icon in the IconFile

The twitch:// protocol will open whatever protocol handler is associated with it, which in this case is Twitch Desktop.  The fuel-launch bit tells Twitch Desktop to open a game with the ID after the next slash, which for Twinkle Star Sprites (in this example) is 66cea04c-bedf-4b41-b484-743ba3424657.

Where’s My Game?

Twitch can throw your game just about anywhere you tell it to, so it’s not like we have a standard place to look for everything.  That being said, there’s a fairly reliable method of finding out: the IconFile property.  We can just search that path for the Fuel ID we got from above and safely assume that’s our game directory.

If that fails, we can try the defaults.  Twitch will try to put games in your Program Files folder (the 32-bit one for some reason) and will also try a Twitch Games folder on every fixed root drive, so iterating through these options gives us some candidates.  If those directories exist and contain a folder named after our Fuel ID, we should be good to go.

Where’s My Game’s EXE?

Twitch’s Fuel link format seems like some kind of impenetrable fortress: the link is processed by a black box program which launches an EXE in a UUID’d folder.  But it’s simpler than it seems.  Each Twitch game (at least of those I’ve tested) contains a fuel.json file with has all the information we could want:

{
  "SchemaVersion":  "2",
  "PostInstall": [
   {
    "Command": "DirectX\\DXSETUP.exe",
    "Args": ["/silent"]
  }
  ],  "Main": {
    "Command": "twinspri.exe",
    "Args": []
  }
}

This JSON object has a Main element at it’s root (at least if SchemaVersion = 2; not sure about other versions), and that Main element has a Command attribute that contains the path to our EXE.  Now we have the path of the EXE and all the meta we need!

Writing a Link

In .Net languages, we have access to the Windows Shell Library, which lets us generate links.

public void WriteStandardLink(string exePath, string linkPath)
{
    var shell = new WshShell();
    WshShortcut shortcut = shell.CreateShortcut(linkPath);
    shortcut.Description = Name;
    shortcut.TargetPath = exePath;
    shortcut.WorkingDirectory = exePath.Substring(0, exePath.LastIndexOf('\\') + 1);
    if (IconPath != null)
    {
        shortcut.IconLocation = IconPath + ',' + IconID;
    }
    shortcut.Save();
}

CreateShortcut does all the work, generating the framework in the location we give it (in this case, the desktop).  We can (and should) give it the properties we got earlier: the name of the game appears as hover text for the link, the EXE we found is the target of the link, the working directory is the folder containing the EXE, and the icon location is the icon path plus the icon index.  We can write this out and get a nice working .lnk to our game!

Downloads and Source

Hosted on GitHub as usual.  Since I finally figured out how GitHub Releases work, I made one, so check here for the latest compiled version.  Please let me know if something doesn’t link right, or if you have a fuel.json file with a version number other than 2.  Best of luck!

3 Replies to “Fix Twitch’s Proprietary Links with Camomile”

  1. Hey man, I don’t know if you’re still around to see this but I hope I could get some help.

    There’s two twitch prime games I’ve come across where the exe doesn’t work and the fuel.json is different. These are Kabounce and Devil May Cry. You gave the fuel.json for most files in this post, but I’m going to post what DMC looks like (and Kabounce looks similar):

    Main:
    Command: “dmcLauncher.exe”
    AuthScopes:
    0: “user_read”
    ClientId: “oo7wrhaawcicykfj6dmfg2jqxhy9yp”

    So there seems to be some authenticity with the client ID. Any idea how to get those EXE opens?

      1. Another game that has this form of “DRM” as well is For the King.

        If you try to launch it via the EXE directly, it will exit after load. Probably fails the check for ClientId# tag.
        If you launch it via the Twitch Desktop App, it will work successfully.

        I still haven’t found a way to pass this check in order for it to launch it via command line, LaunchBox or Steam for instance.

Leave a Reply to JH Cancel reply

Your email address will not be published. Required fields are marked *