Created
July 1, 2021 03:17
-
-
Save rfvgyhn/04a28b484ead9630efe17a45d6afbb6c to your computer and use it in GitHub Desktop.
Lists versions of proton that have been manually specified for steam games
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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