Skip to content

Instantly share code, notes, and snippets.

@rfvgyhn
Created July 1, 2021 03:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rfvgyhn/04a28b484ead9630efe17a45d6afbb6c to your computer and use it in GitHub Desktop.
Save rfvgyhn/04a28b484ead9630efe17a45d6afbb6c to your computer and use it in GitHub Desktop.
Lists versions of proton that have been manually specified for steam games
#!/usr/bin/env -S dotnet fsi
#r "nuget: Gameloop.Vdf"
#r "nuget: Ply"
#r "nuget: Oryx"
open System
open System.IO
open System.Net.Http
open System.Text.Json
open System.Threading.Tasks
open FSharp.Control.Tasks.NonAffine
open Gameloop.Vdf
open Gameloop.Vdf.Linq
open Oryx
let joinWith (separator: string) (values: string seq) = String.Join(separator, values)
let whenAll (tasks: Task<'T> seq) = Task.WhenAll(tasks)
let deserialize (id: string) : IHttpHandler<HttpContent, string> =
let parser stream = task {
let! doc = JsonDocument.ParseAsync stream
return doc.RootElement.GetProperty(id).GetProperty("data").GetProperty("name").ToString()
}
parseAsync parser
type Game = { Id: string; Name: string; Proton: string }
let home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
let path = $"{home}/.steam/root/config/config.vdf"
let httpClient = new HttpClient()
let ctx = HttpContext.defaultContext |> HttpContext.withHttpClient httpClient
let config = VdfConvert.Deserialize(File.ReadAllText(path))
let games =
config.Value.["Software"].["Valve"].["Steam"].["CompatToolMapping"]
|> Seq.map (fun token ->
let prop = token :?> VProperty
let gameId = prop.Key
let protonVersion = prop.Value.Value<string>("name")
{ Id = gameId; Proton = protonVersion; Name = "" }
)
|> Seq.filter (fun game -> game.Proton <> "")
|> Seq.map (fun game -> task {
match!
GET
>=> withUrl "https://store.steampowered.com/api/appdetails"
>=> withQuery [ struct ("appids", game.Id); struct ("filters", "basic") ]
>=> fetch
>=> deserialize game.Id
|> runAsync ctx
with
| Ok name -> return { game with Name = name }
| Error e -> return { game with Name = $"Unknown (Id: {game.Id})" }
})
|> whenAll
games.GetAwaiter().GetResult()
|> Array.groupBy (fun game -> game.Proton)
|> Array.map (fun grp ->
let separator = Environment.NewLine + " "
let proton = fst grp
let games = snd grp |> Array.map (fun game -> game.Name) |> joinWith separator
$"{proton}{separator}{games}")
|> joinWith Environment.NewLine
|> printfn "%s"
httpClient.Dispose()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment