Last active
March 19, 2021 16:30
-
-
Save syntax-tm/82f775e82065a5ab2d7f159fd56d882c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
using System; | |
using System.Collections.Concurrent; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net.Http; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Linq; | |
public class Program | |
{ | |
private const string USER_NAME = "username"; | |
// INSTRUCTIONS: | |
// | |
// 1. Change the above value in quotes from 'username' to a valid username | |
// 2. Click 'Run' | |
// | |
// You might have to click this more than once due to the max execution | |
// time for these scripts being lower than the time it takes to run. So running | |
// it again without a big delay will usually perform the API calls quicker | |
// since it's a REST API and they should be cached. | |
// | |
// tl;dr: Click 'Run' again if nothing shows up | |
// | |
// If you have any questions about this or whatever else, you can contact me via: | |
// | |
// DuckDice : nonon | |
// Discord : Gundwn#6651 | |
// don't change anything below here (unless you want to) | |
private const int COLUMN_WIDTH = 30; | |
private const int FIAT_COLUMN_WIDTH = 18; | |
private const int CRYPTO_PRECISION = 8; | |
private const char USD_SYMBOL = '$'; | |
private const char EURO_SYMBOL = '€'; | |
private const string CURRENCY_URI = "https://duckdice.io/api/currencies"; | |
private const string USER_SEARCH_URI = "https://duckdice.io/api/user/search/{0}"; | |
private const string USER_STATS_URI = "https://duckdice.io/api/user/{0}/{1}"; | |
private static Dictionary<string, DuckDiceCurrency> _currencies = new(); | |
private static ConcurrentDictionary<string, DuckDiceUserStats> _wagered = new(); | |
public static void Main() | |
{ | |
try | |
{ | |
var userHash = GetUserHash(USER_NAME); | |
InitCurrencies(); | |
Parallel.ForEach(_currencies.Keys, symbol => | |
{ | |
var currency = _currencies[symbol]; | |
var wagered = GetUserWageredStat(userHash, currency); | |
_wagered.TryAdd(symbol, wagered); | |
}); | |
// everything after this is just formatting since there are certain | |
// assemblies that aren't usable with this online compiler for security reasons | |
// and the formatting is all done manually (which sucks) | |
var sb = new StringBuilder(); | |
var sortedKeys = _wagered.Values | |
.OrderByDescending(w => w.WageredUsd) | |
.ThenBy(w => w.Currency) | |
.Select(w => w.Currency); | |
foreach (var key in sortedKeys) | |
{ | |
var userStats = _wagered[key]; | |
var amountFmt = ToCryptoFormat(userStats.Wagered, userStats.Currency); | |
var usdFormat = ToFiatFormat(userStats.WageredUsd, USD_SYMBOL); | |
var euroFormat = ToFiatFormat(userStats.WageredEuro, EURO_SYMBOL); | |
sb.AppendLine($"{amountFmt} | {usdFormat} | {euroFormat}"); | |
} | |
var firstLine = sb.ToString().Split(Environment.NewLine)[0]; | |
var lineLength = firstLine.Length; | |
var border = string.Empty.PadLeft(lineLength, '─'); | |
var header = $"User: {USER_NAME} ({userHash})".PadLeft(lineLength, ' '); | |
var usdTotal = _wagered.Values.Sum(w => w.WageredUsd); | |
var euroTotal = _wagered.Values.Sum(w => w.WageredEuro); | |
var usdTotalText = ToFiatFormat(usdTotal, USD_SYMBOL); | |
var euroTotalText = ToFiatFormat(usdTotal, EURO_SYMBOL); | |
var totalSpacing = string.Empty.PadLeft(COLUMN_WIDTH + 3, ' '); | |
Console.WriteLine(header); | |
Console.WriteLine(border); | |
Console.WriteLine(sb); | |
Console.WriteLine(border); | |
Console.WriteLine($"{totalSpacing}{usdTotalText} | {euroTotalText}"); | |
} | |
catch (Exception e) | |
{ | |
var message = e is ArgumentException ? e.Message : e.ToString(); | |
Console.WriteLine(message); | |
} | |
} | |
private static string GetUserHash(string userName) | |
{ | |
try | |
{ | |
var requestUri = string.Format(USER_SEARCH_URI, userName); | |
using var client = new HttpClient(); | |
var response = client.GetStringAsync(requestUri).Result; | |
var doc = JArray.Parse(response); | |
var user = doc.First(e => e.Value<string>("username").Equals(USER_NAME, StringComparison.InvariantCultureIgnoreCase)); | |
var hash = user.Value<string>("hash"); | |
return hash; | |
} | |
catch (Exception e) | |
{ | |
throw new ArgumentException($"Unable to find the user '{USER_NAME}'. Please check the spelling and try again.", e); | |
} | |
} | |
public static DuckDiceUserStats GetUserWageredStat(string userHash, DuckDiceCurrency currency) | |
{ | |
var requestUri = string.Format(USER_STATS_URI, userHash, currency.Symbol); | |
using var client = new HttpClient(); | |
var response = client.GetStringAsync(requestUri).Result; | |
var doc = JObject.Parse(response); | |
var wagered = double.Parse(doc["volume"].ToString()); | |
var stats = new DuckDiceUserStats | |
{ | |
UserHash = userHash, | |
CurrencyInfo = currency, | |
Wagered = wagered | |
}; | |
return stats; | |
} | |
private static string ToFiatFormat(double amount, char currencySymbol, int maxChars = FIAT_COLUMN_WIDTH) | |
{ | |
var amountDisplayText = amount == 0 | |
? "-" | |
: amount.ToString("N2"); | |
var formattedAmount = amountDisplayText.PadLeft(maxChars, ' '); | |
var displayAmount = $"{currencySymbol}{formattedAmount}"; | |
return displayAmount; | |
} | |
private static string ToCryptoFormat(double amount, string label, int precision = CRYPTO_PRECISION, int maxChars = COLUMN_WIDTH) | |
{ | |
var amountStringFormat = $"N{precision}"; | |
var amountDisplayText = amount == 0 | |
? "-" | |
: amount.ToString(amountStringFormat); | |
var labelFormat = label.PadLeft(4, ' '); | |
var formattedValue = $"{amountDisplayText} {labelFormat}"; | |
return formattedValue.PadLeft(maxChars, ' '); | |
} | |
private static void InitCurrencies() | |
{ | |
using var client = new HttpClient(); | |
var currencyResponseText = client.GetStringAsync(CURRENCY_URI).Result; | |
var currencyResponse = JsonConvert.DeserializeObject<DuckDiceCurrency[]>(currencyResponseText); | |
_currencies = currencyResponse.ToDictionary(currency => currency.Symbol); | |
} | |
public class DuckDiceUserStats | |
{ | |
public string UserHash { get; set; } | |
public DuckDiceCurrency CurrencyInfo { get; set; } | |
public double Wagered { get; set; } | |
public string Currency => CurrencyInfo.Symbol; | |
public double WageredUsd => Wagered * CurrencyInfo.PriceUsd; | |
public double WageredEuro => Wagered * CurrencyInfo.PriceEuro; | |
} | |
public class DuckDiceCurrency | |
{ | |
public string Symbol { get; set; } | |
public string Name { get; set; } | |
public double PriceUsd { get; set; } | |
public double PriceEuro { get; set; } | |
public double PriceBtc { get; set; } | |
public override string ToString() => Symbol; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment