Skip to content

Commit 95b8c13

Browse files
authored
Merge pull request mouredev#7166 from Kenysdev/40.cs
mouredev#40 - c#
2 parents 628c344 + a61797d commit 95b8c13

File tree

1 file changed

+191
-0
lines changed

1 file changed

+191
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
namespace exs40;
2+
/*
3+
_____________________________________
4+
https://github.com/kenysdev
5+
2024 - C#
6+
_____________________________________
7+
40 FORTNITE RUBIUS CUP
8+
------------------------------------
9+
10+
* EJERCICIO:
11+
* ¡Rubius tiene su propia skin en Fortnite!
12+
* Y va a organizar una competición para celebrarlo.
13+
* Esta es la lista de participantes:
14+
* https://x.com/Rubiu5/status/1840161450154692876
15+
*
16+
* Desarrolla un programa que obtenga el número de seguidores en
17+
* Twitch de cada participante, la fecha de creación de la cuenta
18+
* y ordene los resultados en dos listados.
19+
* - Usa el API de Twitch: https://dev.twitch.tv/docs/api/reference
20+
* (NO subas las credenciales de autenticación)
21+
* - Crea un ranking por número de seguidores y por antigüedad.
22+
* - Si algún participante no tiene usuario en Twitch, debe reflejarlo.
23+
*/
24+
25+
using System.Net.Http;
26+
using System.Text.Json;
27+
// https://www.nuget.org/packages/DotNetEnv/
28+
using DotNetEnv;
29+
30+
public class Twitch(string clientId, string clientSecret)
31+
{
32+
private readonly string clientId = clientId;
33+
private readonly string clientSecret = clientSecret;
34+
private string? accessToken;
35+
36+
public class UserData
37+
{
38+
public required string Username { get; set; }
39+
public DateTime CreatedAt { get; set; }
40+
public int Followers { get; set; }
41+
}
42+
43+
private async Task EnsureAccessTokenAsync()
44+
{
45+
if (string.IsNullOrEmpty(accessToken))
46+
{
47+
using var client = new HttpClient();
48+
var tokenContent = new FormUrlEncodedContent(new Dictionary<string, string>
49+
{
50+
{ "client_id", clientId },
51+
{ "client_secret", clientSecret },
52+
{ "grant_type", "client_credentials" }
53+
});
54+
55+
var tokenResponse = await client.PostAsync("https://id.twitch.tv/oauth2/token", tokenContent);
56+
57+
if (!tokenResponse.IsSuccessStatusCode)
58+
{
59+
throw new Exception($"Error al obtener el token: {tokenResponse.StatusCode}");
60+
}
61+
62+
var tokenJson = await tokenResponse.Content.ReadAsStringAsync();
63+
var tokenData = JsonSerializer.Deserialize<JsonElement>(tokenJson);
64+
accessToken = tokenData.GetProperty("access_token").GetString();
65+
}
66+
}
67+
68+
private static async Task<int> GetFollowers(HttpClient client, string? idUser)
69+
{
70+
var response = await client.GetAsync($"https://api.twitch.tv/helix/channels/followers?broadcaster_id={idUser}");
71+
var json = await response.Content.ReadAsStringAsync();
72+
var data = JsonSerializer.Deserialize<JsonElement>(json);
73+
var total = data.GetProperty("total").GetInt32();
74+
return total;
75+
}
76+
77+
private async Task<UserData?> GetUserData(string userName)
78+
{
79+
await EnsureAccessTokenAsync();
80+
81+
using var client = new HttpClient();
82+
client.DefaultRequestHeaders.Add("Client-Id", clientId);
83+
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
84+
85+
var response = await client.GetAsync($"https://api.twitch.tv/helix/users?login={userName}");
86+
var json = await response.Content.ReadAsStringAsync();
87+
var data = JsonSerializer.Deserialize<JsonElement>(json);
88+
if (data.GetProperty("data").EnumerateArray().Any())
89+
{
90+
var dt = data.GetProperty("data")[0];
91+
var idUser = dt.GetProperty("id").GetString();
92+
var createdAtString = dt.GetProperty("created_at").GetString();
93+
94+
if (createdAtString != null)
95+
{
96+
var createdAt = DateTime.Parse(createdAtString);
97+
var totalFolowers = await GetFollowers(client, idUser);
98+
99+
return new UserData
100+
{
101+
Username = userName,
102+
CreatedAt = createdAt,
103+
Followers = totalFolowers
104+
};
105+
}
106+
}
107+
return null;
108+
}
109+
110+
public class Program
111+
{
112+
private static void PrintRankings(List<UserData> usersData)
113+
{
114+
var byFollowers = usersData.OrderByDescending(x => x.Followers).ToList();
115+
var byDate = usersData.OrderBy(x => x.CreatedAt).ToList();
116+
117+
Console.WriteLine("\nRanking por número de seguidores:");
118+
for (int i = 0; i < byFollowers.Count; i++)
119+
{
120+
Console.WriteLine($"{i + 1} - {byFollowers[i].Username}: {byFollowers[i].Followers:N0} seguidores");
121+
}
122+
123+
Console.WriteLine("\nRanking por antigüedad:");
124+
for (int i = 0; i < byDate.Count; i++)
125+
{
126+
Console.WriteLine($"{i + 1} - {byDate[i].Username}: Creado el {byDate[i].CreatedAt:dd/MM/yyyy}");
127+
}
128+
}
129+
130+
public static async Task ProcessUsers(List<string> users, Twitch Tw)
131+
{
132+
133+
var usersData = new List<UserData>();
134+
var notFoundUsers = new List<string>();
135+
136+
Console.WriteLine("Obteniendo datos...");
137+
138+
foreach (var name in users)
139+
{
140+
var userData = await Tw.GetUserData(name);
141+
if (userData != null)
142+
{
143+
usersData.Add(userData);
144+
}
145+
else
146+
{
147+
notFoundUsers.Add(name);
148+
}
149+
}
150+
151+
PrintRankings(usersData);
152+
153+
if (notFoundUsers.Count != 0)
154+
{
155+
Console.WriteLine("\nUsuarios no encontrados:");
156+
foreach (var user in notFoundUsers)
157+
{
158+
Console.WriteLine(user);
159+
}
160+
}
161+
}
162+
}
163+
164+
public static async Task Main()
165+
{
166+
Env.Load();
167+
string clientId = Environment.GetEnvironmentVariable("TWITCH_CLIENT_ID") ?? "defaultClientId";
168+
string clientSecret = Environment.GetEnvironmentVariable("TWITCH_CLIENT_SECRET") ?? "defaultClientSecret";
169+
var Tw = new Twitch(clientId, clientSecret);
170+
171+
var users = new List<string>
172+
{
173+
"abby", "ache", "adricontreras", "agustin", "alexby", "ampeter", "ander", "arigameplays",
174+
"arigeli", "auronplay", "axozer", "beniju", "bycalitos", "byviruzz", "carrera", "celopan",
175+
"cheeto", "crystalmolly", "darioemehache", "dheyo",
176+
"djmario", "doble", "elvisa", "elyas360", "folagor", "grefg", "guanyar", "hika",
177+
"hiper", "ibai", "ibelky", "illojuan", "imantado", "irinaisasia", "jesskiu", "jopa",
178+
"jordiwild", "kenaisouza", "keroro", "kiddkeo",
179+
"kikorivera", "knekro", "koko", "kronnozomber", "leviathan", "litkillah", "lolalolita", "lolito",
180+
"luh", "luzu", "mangel", "mayichi", "melo", "missasinonia", "mixwell", "mrjagger",
181+
"nategentile", "nexxuz", "nia", "nilojeda",
182+
"nissaxter", "ollie", "orslok", "outconsumer", "papigavi", "paracetamor", "patica", "paulagonu",
183+
"pausenpaii", "perxitaa", "plex", "polispol", "quackity", "recuerdop", "reven", "rivers",
184+
"robertpg", "roier", "rojuu", "rubius",
185+
"shadoune", "silithur", "spoksponha", "spreen", "spursito", "staxx", "suzyroxx", "vicens",
186+
"vituber", "werlyb", "xavi", "xcry", "xokas", "zarcort", "zeling", "zorman"
187+
};
188+
189+
await Program.ProcessUsers(users, Tw);
190+
}
191+
}

0 commit comments

Comments
 (0)