Skip to content

Commit ae7c6b9

Browse files
committed
major "refactoring", no longer requires external .exe
1 parent cbbe55a commit ae7c6b9

24 files changed

+313
-49
lines changed

BonusTools.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using BonusTools.JP;
2-
using BonusTools.JP.ImportFromFiles;
1+
using BonusTools;
2+
using BonusTools.ImportFromFiles;
33
using Playnite.SDK;
44
using Playnite.SDK.Plugins;
55
using System;
@@ -13,9 +13,6 @@ public class BonusTools : GenericPlugin
1313
{
1414
private static readonly ILogger logger = LogManager.GetLogger();
1515
private string steamApiLanguage;
16-
private const string CLIENT_ID = "____";
17-
private const string CLIENT_SECRET = "____";
18-
1916

2017
public override Guid Id { get; } = Guid.Parse("ca24e37a-76d9-49bf-89ab-d3cba4a54bd2");
2118

BonusTools.csproj

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
44
<PropertyGroup>
5+
<LangVersion>8.0</LangVersion>
6+
<Nullable>enable</Nullable>
57
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
68
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
79
<ProjectGuid>{E63CAD2F-E238-4F0B-B294-90810D6134B2}</ProjectGuid>
810
<OutputType>Library</OutputType>
911
<AppDesignerFolder>Properties</AppDesignerFolder>
10-
<RootNamespace>ReviewViewer</RootNamespace>
11-
<AssemblyName>ReviewViewer</AssemblyName>
12-
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
12+
<RootNamespace>BonusTools</RootNamespace>
13+
<AssemblyName>BonusTools</AssemblyName>
14+
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
1315
<FileAlignment>512</FileAlignment>
1416
<Deterministic>true</Deterministic>
1517
<NuGetPackageImportStamp>
1618
</NuGetPackageImportStamp>
19+
<TargetFrameworkProfile />
1720
</PropertyGroup>
1821
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
1922
<DebugSymbols>true</DebugSymbols>
@@ -49,6 +52,9 @@
4952
<Reference Include="HtmlRenderer.WPF, Version=1.5.0.6, Culture=neutral, processorArchitecture=MSIL">
5053
<HintPath>..\..\packages\HtmlRenderer.WPF.1.5.0.6\lib\net45\HtmlRenderer.WPF.dll</HintPath>
5154
</Reference>
55+
<Reference Include="IGDB, Version=5.1.0.0, Culture=neutral, processorArchitecture=MSIL">
56+
<HintPath>packages\IGDB.5.1.0\lib\netstandard2.0\IGDB.dll</HintPath>
57+
</Reference>
5258
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
5359
<HintPath>packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
5460
</Reference>
@@ -234,8 +240,15 @@
234240
<Compile Include="..\..\Common\SteamCommon\Common.cs">
235241
<Link>Shared\SteamCommon\Common.cs</Link>
236242
</Compile>
243+
<Compile Include="IGDBexe\GameJson.cs" />
244+
<Compile Include="IGDBexe\GameParser.cs" />
245+
<Compile Include="IGDBexe\IGDBEndpointExtensions.cs" />
246+
<Compile Include="IGDBexe\PopularityPrimitive.cs" />
247+
<Compile Include="IGDBexe\PopularitySource.cs" />
248+
<Compile Include="IGDBexe\PopularityType.cs" />
249+
<Compile Include="IGDBexe\Program.cs" />
250+
<Compile Include="IGDBexe\TestData.cs" />
237251
<Compile Include="JP\ImportFromFiles\CustomSpreadsheet.cs" />
238-
<Compile Include="JP\Models\GameJson.cs" />
239252
<Compile Include="JP\Popularity\IGDB.cs" />
240253
<Compile Include="JP\ImportFromFiles\Nintendo.cs" />
241254
<Compile Include="JP\ImportFromFiles\PsPrices.cs" />

JP/Models/GameJson.cs renamed to IGDBexe/GameJson.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.IO;
55
using System.Collections.Generic;
66

7-
namespace BonusTools.JP
7+
namespace BonusTools
88
{
99
public class GameExport
1010
{

IGDBexe/GameParser.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System.Text.Json;
2+
using System.IO;
3+
using System;
4+
5+
namespace BonusTools
6+
{
7+
public class GameStatsParser
8+
{
9+
/// <summary>
10+
/// Reads and parses game statistics from a JSON file
11+
/// </summary>
12+
/// <param name="filePath">Path to the JSON file</param>
13+
/// <returns>Parsed GameExport object</returns>
14+
public static GameExport? ParseGameStats(string filePath)
15+
{
16+
try
17+
{
18+
string jsonString = File.ReadAllText(filePath);
19+
var options = new JsonSerializerOptions
20+
{
21+
PropertyNameCaseInsensitive = true
22+
};
23+
24+
return JsonSerializer.Deserialize<GameExport>(jsonString, options);
25+
}
26+
catch (FileNotFoundException)
27+
{
28+
throw new FileNotFoundException($"JSON file not found at path: {filePath}");
29+
}
30+
catch (JsonException ex)
31+
{
32+
throw new JsonException($"Error parsing JSON: {ex.Message}");
33+
}
34+
catch (Exception ex)
35+
{
36+
throw new Exception($"Unexpected error: {ex.Message}");
37+
}
38+
}
39+
40+
// Example usage of how to print game statistics
41+
//public static void PrintGameStats(GameExport gameExport)
42+
//{
43+
// Console.WriteLine($"Export Date: {gameExport.ExportString}");
44+
// Console.WriteLine($"Version: {gameExport.ExportVersion}");
45+
46+
// foreach (var user in gameExport.Users)
47+
// {
48+
// Console.WriteLine($"\nUser: {user.Name} (ID: {user.Id})");
49+
// foreach (var title in user.Titles)
50+
// {
51+
// Console.WriteLine($"\nGame: {title.Name}");
52+
// Console.WriteLine($"First Played: {DateTimeOffset.FromUnixTimeSeconds(title.Summary.FirstPlayed)}");
53+
// Console.WriteLine($"Last Played: {DateTimeOffset.FromUnixTimeSeconds(title.Summary.LastPlayed)}");
54+
// Console.WriteLine($"Total Launches: {title.Summary.Launches}");
55+
// Console.WriteLine($"Playtime (seconds): {title.Summary.Playtime}");
56+
// }
57+
// }
58+
//}
59+
}
60+
61+
}

IGDBexe/IGDBEndpointExtensions.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace BonusTools
8+
{
9+
public static class Endpoints
10+
{
11+
public const string PopularityTypes = "popularity_types";
12+
public const string PopularityPrimitives = "popularity_primitives";
13+
}
14+
}

IGDBexe/PopularityPrimitive.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using IGDB;
2+
using IGDB.Models;
3+
using System;
4+
using System.Text.Json.Serialization;
5+
6+
namespace BonusTools
7+
{
8+
public class CustomGame : Game
9+
{
10+
11+
[JsonPropertyName("popularity_type")]
12+
public int PopularityType { get; set; }
13+
14+
}
15+
16+
public class PopularityPrimitive : ITimestamps //, IHasChecksum
17+
{
18+
public DateTimeOffset? CalculatedAt { get; set; }
19+
/*
20+
* Even though the IGDB API documentation states that the checksum field
21+
* is available for this model, the API does not return it. This is why
22+
* the Checksum property is commented out for now.
23+
*/
24+
//public string Checksum { get; set; }
25+
public DateTimeOffset? CreatedAt { get; set; }
26+
public long? GameId { get; set; }
27+
public PopularitySource? PopularitySource { get; set; }
28+
public IdentityOrValue<PopularityType> PopularityType { get; set; }
29+
public DateTimeOffset? UpdatedAt { get; set; }
30+
public decimal? Value { get; set; }
31+
}
32+
}

IGDBexe/PopularitySource.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace BonusTools
2+
{
3+
public enum PopularitySource
4+
{
5+
Igdb = 121
6+
}
7+
}

IGDBexe/PopularityType.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using IGDB.Models;
2+
using System;
3+
using System.Text.Json.Serialization;
4+
5+
namespace BonusTools
6+
{
7+
public class PopularityType : ITimestamps, IHasChecksum
8+
{
9+
public string Checksum { get; set; }
10+
public DateTimeOffset? CreatedAt { get; set; }
11+
12+
[JsonPropertyName("id")]
13+
public long Id { get; set; }
14+
15+
[JsonPropertyName("name")]
16+
public string Name { get; set; }
17+
18+
public PopularitySource? PopularitySource { get; set; }
19+
public DateTimeOffset? UpdatedAt { get; set; }
20+
}
21+
}

IGDBexe/Program.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using IGDB;
2+
using IGDB.Models;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace BonusTools
8+
{
9+
public class Program
10+
{
11+
// TODO : ask users to provide their own API key ?
12+
// see https://api-docs.igdb.com/#getting-started
13+
private const string CLIENT_ID = "j8jsa14md3xge0nkdn9d0sjh56svqp";
14+
private const string CLIENT_SECRET = "4j6o7t555ix3j2bm1jyscwyyvybc10";
15+
16+
public const string PopularityPrimitives = "popularity_primitives";
17+
public const string PopularityTypes = "popularity_types";
18+
19+
// This is used by Playnite BonusTools extension to get the number of reviews of a game, which is then used for the UserScore
20+
public static string Main(string gameName)
21+
{
22+
var api = new IGDBClient(CLIENT_ID, CLIENT_SECRET);
23+
var result = GetRatingCount(gameName, api).Result;
24+
return result;
25+
}
26+
27+
private static async Task<string> GetRatingCount(string gameName, IGDBClient api)
28+
{
29+
Game? igdbGame = await SearchByName(gameName, api);
30+
// Average rating based on IGDB users only = community score
31+
// Total number of user and external critic scores
32+
var data = $"{igdbGame?.Rating}|{igdbGame?.TotalRatingCount}";
33+
return data;
34+
}
35+
36+
public static async Task<Game?> SearchByName(string gameName, IGDBClient api)
37+
{
38+
var igdbGames = await api.QueryAsync<Game>(
39+
IGDBClient.Endpoints.Games,
40+
$"fields name, id, rating,total_rating_count; where name ~ *\"{gameName}\"*; sort total_rating_count desc;"
41+
);
42+
43+
var igdbGame = igdbGames.FirstOrDefault();
44+
//Console.WriteLine($"Found Game: {igdbGame?.Name}");
45+
return igdbGame;
46+
}
47+
}
48+
}

IGDBexe/TestData.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace BonusTools
8+
{
9+
public static class TestData
10+
{
11+
public static string[] GetTestData()
12+
{
13+
//Found Game: The Legend of Zelda: Breath of the Wild
14+
//Pop score: 446.579538899000000
15+
//Found Game: Red Dead Redemption 2
16+
//Pop score: 749.93535040066666666666666667
17+
//Found Game: Grand Theft Auto V
18+
//Pop score: 321.25877742633333333333333333
19+
//Found Game: The Witcher 3: Wild Hunt
20+
//Pop score: 553.99733444733333333333333333
21+
//Found Game: Super Mario Odyssey
22+
//Pop score: 249.64691372766666666666666667
23+
//Found Game: God of War
24+
//Pop score: 573.889518808000000
25+
//Found Game: Minecraft: Java Edition
26+
//Pop score: 84.54178353333333333333333333
27+
//Found Game: The Last of Us
28+
//Pop score: 302.36120228366666666666666667
29+
//Found Game: Portal 2
30+
//Pop score: 242.68464920133333333333333333
31+
//Found Game: Half-Life 2
32+
//Pop score: 210.857154224000000
33+
34+
return new string[]
35+
{
36+
"The Legend of Zelda: Breath of the Wild",
37+
"Red Dead Redemption 2",
38+
"Grand Theft Auto V",
39+
"The Witcher 3: Wild Hunt",
40+
"Super Mario Odyssey",
41+
"God of War",
42+
"Minecraft",
43+
"The Last of Us",
44+
"Portal 2",
45+
"Half-Life 2"
46+
};
47+
}
48+
}
49+
}

JP/ImportFromFiles/CustomSpreadsheet.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
using System.Text;
1010
using System.Threading.Tasks;
1111

12-
namespace BonusTools.JP
12+
namespace BonusTools
1313
{
1414
// Warning : Price will be imported in Version field !!
1515
// Only import games that have a price

JP/ImportFromFiles/Nintendo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
using System.Text.Json;
99
using System.Threading.Tasks;
1010

11-
namespace BonusTools.JP
11+
namespace BonusTools
1212
{
1313
internal class Nintendo
1414
{

JP/ImportFromFiles/PsPrices.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
using System.Text;
1010
using System.Threading.Tasks;
1111

12-
namespace BonusTools.JP
12+
namespace BonusTools
1313
{
1414
internal class PsPrices
1515
{

JP/ImportFromFiles/Ryujinx.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
using System.Threading.Tasks;
1212
using System.Xml.Linq;
1313

14-
namespace BonusTools.JP.ImportFromFiles
14+
namespace BonusTools.ImportFromFiles
1515
{
1616
internal class Ryujinx
1717
{

JP/ImportFromFiles/Yuzu.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
using System.Threading.Tasks;
1212
using System.Xml.Linq;
1313

14-
namespace BonusTools.JP.ImportFromFiles
14+
namespace BonusTools.ImportFromFiles
1515
{
1616
internal class Yuzu
1717
{

JP/Popularity/IGDB.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
using System.Threading.Tasks;
99
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
1010

11-
namespace BonusTools.JP
11+
namespace BonusTools
1212
{
1313
public class IGDB
1414
{
@@ -22,7 +22,9 @@ public static Task UpdateScores(Game playniteGame, IPlayniteAPI PlayniteApi)
2222
string cleanName = RemoveEditions(gameToUpdate.Name);
2323

2424
// TODO : need to stop relying on an external program
25-
string output = ExecuteExternalProgram(@"C:\Users\JP\source\repos\NintendoSwitch\IGDB\bin\Debug\net8.0\IGDBexe.exe", "\"" + cleanName + "\"");
25+
//string output = ExecuteExternalProgram(@"C:\Users\JP\source\repos\NintendoSwitch\IGDB\bin\Debug\net8.0\IGDBexe.exe", "\"" + cleanName + "\"");
26+
27+
string output = Program.Main(cleanName);
2628
string[] results = output.Trim().Split('|');
2729

2830
// Try to parse the sum

JP/Popularity/Popularity.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
using Playnite.SDK.Models;
22
using Playnite.SDK;
3-
using System;
43
using System.Collections.Generic;
54
using System.Linq;
6-
using System.Text;
7-
using System.Threading.Tasks;
8-
using BonusTools.JP;
9-
using Playnite.SDK.Plugins;
5+
using BonusTools;
106

117
namespace BonusTools
128
{

0 commit comments

Comments
 (0)