Skip to content

Commit 75a2d01

Browse files
committed
Merge branch 'dev'
2 parents d9fd051 + 6cfddfa commit 75a2d01

File tree

12 files changed

+143
-88
lines changed

12 files changed

+143
-88
lines changed

.claude/settings.local.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
"Bash(git log:*)",
1414
"Bash(wc:*)",
1515
"Bash(grep:*)",
16-
"Bash(dotnet test:*)"
16+
"Bash(dotnet test:*)",
17+
"WebFetch(domain:ffmpeg.org)",
18+
"WebFetch(domain:www.ffmpeg.org)"
1719
]
1820
}
1921
}

src/FMBot.Bot/Builders/AlbumBuilders.cs

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,21 +1245,6 @@ public async Task<ResponseModel> CoverAsync(
12451245
return response;
12461246
}
12471247

1248-
var image = await this._dataSourceFactory.GetAlbumImageAsStreamAsync(albumCoverUrl);
1249-
if (image == null)
1250-
{
1251-
response.Embed.WithDescription("Sorry, something went wrong while getting album cover for this album: \n" +
1252-
$"{albumSearch.Album.ArtistName} - {albumSearch.Album.AlbumName}\n" +
1253-
$"[View on last.fm]({albumSearch.Album.AlbumUrl})");
1254-
response.CommandResponse = CommandResponse.Error;
1255-
response.ResponseType = ResponseType.Embed;
1256-
return response;
1257-
}
1258-
1259-
var cacheStream = new MemoryStream();
1260-
await image.CopyToAsync(cacheStream);
1261-
image.Position = 0;
1262-
12631248
var description = new StringBuilder();
12641249
description.AppendLine(
12651250
$"**[{albumSearch.Album.ArtistName}]({albumSearch.Album.ArtistUrl}) - [{albumSearch.Album.AlbumName}]({albumSearch.Album.AlbumUrl})**");
@@ -1273,48 +1258,77 @@ public async Task<ResponseModel> CoverAsync(
12731258
$"-# *Requested by {await UserService.GetNameAsync(context.DiscordGuild, context.DiscordUser)}*");
12741259

12751260
response.Embed.WithDescription(description.ToString());
1276-
1277-
response.Stream = image;
1278-
var extension = gifResult ? "webp" : "png";
1279-
response.FileName =
1280-
$"cover-{StringExtensions.ReplaceInvalidChars($"{albumSearch.Album.ArtistName}_{albumSearch.Album.AlbumName}")}.{extension}";
12811261
response.Spoiler = safeForChannel == CensorService.CensorResult.Nsfw;
12821262
response.FileDescription = StringExtensions.TruncateLongString($"Album cover for {albumSearch.Album.AlbumName} by {albumSearch.Album.ArtistName}", 512);
12831263

1284-
if (!gifResult)
1285-
{
1286-
var cacheFilePath =
1287-
ChartService.AlbumUrlToCacheFilePath(albumSearch.Album.AlbumName, albumSearch.Album.ArtistName);
1288-
await ChartService.OverwriteCache(cacheStream, cacheFilePath);
1289-
}
1290-
else
1264+
if (gifResult)
12911265
{
12921266
var cacheFilePath =
12931267
ChartService.AlbumUrlToCacheFilePath(albumSearch.Album.AlbumName, albumSearch.Album.ArtistName,
12941268
".webp");
1295-
Stream gifStream;
12961269

1297-
if (!File.Exists(cacheFilePath))
1270+
Stream gifStream;
1271+
if (File.Exists(cacheFilePath))
12981272
{
1299-
var specificUrl = await this._appleMusicVideoService.GetVideoUrlFromM3U8(albumCoverUrl);
1300-
gifStream = await AppleMusicVideoService.ConvertM3U8ToWebPAsync(specificUrl);
1301-
await ChartService.OverwriteCache(gifStream, cacheFilePath, SKEncodedImageFormat.Webp);
1273+
var memoryStream = new MemoryStream();
1274+
await using (var fileStream = File.OpenRead(cacheFilePath))
1275+
{
1276+
await fileStream.CopyToAsync(memoryStream);
1277+
}
1278+
memoryStream.Position = 0;
1279+
gifStream = memoryStream;
13021280
}
13031281
else
13041282
{
1305-
gifStream = File.OpenRead(cacheFilePath);
1283+
var specificUrl = await this._appleMusicVideoService.GetVideoUrlFromM3U8(albumCoverUrl);
1284+
gifStream = await AppleMusicVideoService.ConvertM3U8ToWebPAsync(specificUrl);
1285+
try
1286+
{
1287+
await ChartService.OverwriteCache(gifStream, cacheFilePath, SKEncodedImageFormat.Webp);
1288+
}
1289+
catch (IOException)
1290+
{
1291+
// Cache write failed due to concurrent access, not critical
1292+
}
1293+
gifStream.Position = 0;
13061294
}
13071295

13081296
response.Stream = gifStream;
1297+
response.FileName =
1298+
$"cover-{StringExtensions.ReplaceInvalidChars($"{albumSearch.Album.ArtistName}_{albumSearch.Album.AlbumName}")}.webp";
1299+
}
1300+
else
1301+
{
1302+
var image = await this._dataSourceFactory.GetAlbumImageAsStreamAsync(albumCoverUrl);
1303+
if (image == null)
1304+
{
1305+
response.Embed.WithDescription("Sorry, something went wrong while getting album cover for this album: \n" +
1306+
$"{albumSearch.Album.ArtistName} - {albumSearch.Album.AlbumName}\n" +
1307+
$"[View on last.fm]({albumSearch.Album.AlbumUrl})");
1308+
response.CommandResponse = CommandResponse.Error;
1309+
response.ResponseType = ResponseType.Embed;
1310+
return response;
1311+
}
1312+
1313+
var cacheStream = new MemoryStream();
1314+
await image.CopyToAsync(cacheStream);
1315+
image.Position = 0;
1316+
1317+
response.Stream = image;
1318+
response.FileName =
1319+
$"cover-{StringExtensions.ReplaceInvalidChars($"{albumSearch.Album.ArtistName}_{albumSearch.Album.AlbumName}")}.png";
1320+
1321+
var cacheFilePath =
1322+
ChartService.AlbumUrlToCacheFilePath(albumSearch.Album.AlbumName, albumSearch.Album.ArtistName);
1323+
await ChartService.OverwriteCache(cacheStream, cacheFilePath);
1324+
await cacheStream.DisposeAsync();
13091325
}
13101326

13111327
var accentColor = await this._albumService.GetAccentColorWithAlbum(context,
13121328
staticAlbumCoverUrl, databaseAlbum?.Id, albumSearch.Album.AlbumName, albumSearch.Album.ArtistName);
13131329

13141330
response.Embed.WithColor(accentColor);
13151331

1316-
await cacheStream.DisposeAsync();
1317-
13181332
return response;
13191333
}
13201334

src/FMBot.Bot/Builders/StaticBuilders.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,21 +284,21 @@ public async Task<ResponseModel> BuildGiftSupporterResponse(ulong purchaserDisco
284284
{
285285
response.Embed.AddField($"Quarter - {pricing.QuarterlyPriceString}",
286286
$"-# {pricing.QuarterlySubText}", true);
287-
actionRow.WithButton("Gift quarter", $"gift-supporter-purchase-quarterly-{recipient.DiscordUserId}");
287+
actionRow.WithButton("Gift quarter", $"gift-supporter-purchase:quarterly:{recipient.DiscordUserId}");
288288
}
289289

290290
if (!string.IsNullOrEmpty(pricing.YearlyPriceId))
291291
{
292292
response.Embed.AddField($"Yearly - {pricing.YearlyPriceString}",
293293
$"-# {pricing.YearlySubText}", true);
294-
actionRow.WithButton("Gift year", $"gift-supporter-purchase-yearly-{recipient.DiscordUserId}");
294+
actionRow.WithButton("Gift year", $"gift-supporter-purchase:yearly:{recipient.DiscordUserId}");
295295
}
296296

297297
if (!string.IsNullOrEmpty(pricing.TwoYearPriceId))
298298
{
299299
response.Embed.AddField($"Two years - {pricing.TwoYearPriceString}",
300300
$"-# {pricing.TwoYearSubText}", true);
301-
actionRow.WithButton("Gift two years", $"gift-supporter-purchase-twoyear-{recipient.DiscordUserId}");
301+
actionRow.WithButton("Gift two years", $"gift-supporter-purchase:twoyear:{recipient.DiscordUserId}");
302302
}
303303

304304
// if (!string.IsNullOrEmpty(pricing.LifetimePriceId))

src/FMBot.Bot/Builders/TrackBuilders.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,7 +1148,7 @@ public async Task<ResponseModel> GuildTracksAsync(
11481148
};
11491149

11501150
ICollection<GuildTrack> topGuildTracks;
1151-
IList<GuildTrack> previousTopGuildTracks = null;
1151+
List<GuildTrack> previousTopGuildTracks = null;
11521152
if (guildListSettings.ChartTimePeriod == TimePeriod.AllTime)
11531153
{
11541154
topGuildTracks = await this._whoKnowsTrackService.GetTopAllTimeTracksForGuild(guild.GuildId,
@@ -1165,7 +1165,7 @@ public async Task<ResponseModel> GuildTracksAsync(
11651165
guildListSettings.OrderType, guildListSettings.NewSearchValue);
11661166
}
11671167

1168-
if (!topGuildTracks.Any())
1168+
if (topGuildTracks.Count == 0)
11691169
{
11701170
response.Embed.WithDescription(guildListSettings.NewSearchValue != null
11711171
? $"Sorry, there are no registered top tracks for artist `{guildListSettings.NewSearchValue}` on this server in the time period you selected."

src/FMBot.Bot/Extensions/InteractionContextExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@ public async Task SendResponse(InteractiveService interactiveService, ResponseMo
329329
.WithFlags(flags)
330330
.WithComponents(response.GetMessageComponents())));
331331
interactionResponseId = imageWithEmbed?.Interaction.ResponseMessageId;
332+
333+
if (response.Stream != null)
334+
{
335+
await response.Stream.DisposeAsync();
336+
}
337+
332338
break;
333339
case ResponseType.Paginator:
334340
var paginator = await interactiveService.SendPaginatorAsync(

src/FMBot.Bot/Services/Guild/GuildService.cs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,28 @@ public async Task<IDictionary<int, FullGuildUser>> GetGuildUsers(ulong? discordG
141141
return result.ToDictionary(d => d.UserId, d => d);
142142
}
143143

144+
public async Task<int> GetGuildUserCount(ulong? discordGuildId = null)
145+
{
146+
if (discordGuildId == null)
147+
{
148+
return 0;
149+
}
150+
151+
const string sql = "SELECT COUNT(*) " +
152+
"FROM public.guild_users AS gu " +
153+
"LEFT JOIN guilds AS g ON gu.guild_id = g.guild_id " +
154+
"WHERE g.discord_guild_id = @discordGuildId";
155+
156+
DefaultTypeMap.MatchNamesWithUnderscores = true;
157+
await using var connection = new NpgsqlConnection(this._botSettings.Database.ConnectionString);
158+
await connection.OpenAsync();
159+
160+
return await connection.ExecuteScalarAsync<int>(sql, new
161+
{
162+
discordGuildId = Convert.ToInt64(discordGuildId)
163+
});
164+
}
165+
144166
public async Task<List<Persistence.Domain.Models.Guild>> GetPremiumGuilds()
145167
{
146168
await using var db = await this._contextFactory.CreateDbContextAsync();
@@ -294,29 +316,6 @@ public static async Task<Permissions> GetGuildPermissionsAsync(ApplicationComman
294316
return guildUser.GetPermissions(guild);
295317
}
296318

297-
public static GuildUser GetUserFromGuild(Persistence.Domain.Models.Guild guild, int userId)
298-
{
299-
return guild.GuildUsers
300-
.FirstOrDefault(f => f.UserId == userId);
301-
}
302-
303-
public async Task StaleGuildLastIndexedAsync(NetCord.Gateway.Guild discordGuild)
304-
{
305-
await using var db = await this._contextFactory.CreateDbContextAsync();
306-
var existingGuild = await db.Guilds
307-
.AsQueryable()
308-
.FirstAsync(f => f.DiscordGuildId == discordGuild.Id);
309-
310-
existingGuild.Name = discordGuild.Name;
311-
existingGuild.LastIndexed = null;
312-
313-
db.Entry(existingGuild).State = EntityState.Modified;
314-
315-
await db.SaveChangesAsync();
316-
317-
await RemoveGuildFromCache(discordGuild.Id);
318-
}
319-
320319
public async Task ChangeGuildAllowedRoles(NetCord.Gateway.Guild discordGuild, ulong[] allowedRoles)
321320
{
322321
await using var db = await this._contextFactory.CreateDbContextAsync();

src/FMBot.Bot/SlashCommands/ServerSlashCommands.cs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public async Task GuildArtistsAsync(
3939
await RespondAsync(InteractionCallback.DeferredMessage());
4040

4141
var guild = await guildService.GetGuildAsync(this.Context.Guild.Id);
42+
var guildUserCount = await guildService.GetGuildUserCount(this.Context.Guild.Id);
4243

4344
var guildListSettings = new GuildRankingSettings
4445
{
@@ -49,10 +50,11 @@ public async Task GuildArtistsAsync(
4950
};
5051

5152
var timeSettings =
52-
SettingService.GetTimePeriod(Enum.GetName(typeof(PlayTimePeriod), timePeriod), TimePeriod.AllTime);
53+
SettingService.GetTimePeriod(Enum.GetName(timePeriod), TimePeriod.AllTime);
5354

5455
if (timeSettings.UsePlays ||
55-
timeSettings.TimePeriod is TimePeriod.AllTime or TimePeriod.Monthly or TimePeriod.Weekly)
56+
timeSettings.TimePeriod is TimePeriod.AllTime or TimePeriod.Weekly ||
57+
(timeSettings.TimePeriod is TimePeriod.Monthly && guildUserCount <= 10000))
5658
{
5759
guildListSettings = SettingService.TimeSettingsToGuildRankingSettings(guildListSettings, timeSettings);
5860
}
@@ -79,6 +81,7 @@ public async Task GuildAlbumsAsync(
7981
await RespondAsync(InteractionCallback.DeferredMessage());
8082

8183
var guild = await guildService.GetGuildAsync(this.Context.Guild.Id);
84+
var guildUserCount = await guildService.GetGuildUserCount(this.Context.Guild.Id);
8285

8386
var guildListSettings = new GuildRankingSettings
8487
{
@@ -90,10 +93,11 @@ public async Task GuildAlbumsAsync(
9093
};
9194

9295
var timeSettings =
93-
SettingService.GetTimePeriod(Enum.GetName(typeof(PlayTimePeriod), timePeriod), TimePeriod.AllTime);
96+
SettingService.GetTimePeriod(Enum.GetName(timePeriod), TimePeriod.AllTime);
9497

9598
if (timeSettings.UsePlays ||
96-
timeSettings.TimePeriod is TimePeriod.AllTime or TimePeriod.Monthly or TimePeriod.Weekly)
99+
timeSettings.TimePeriod is TimePeriod.AllTime or TimePeriod.Weekly ||
100+
(timeSettings.TimePeriod is TimePeriod.Monthly && guildUserCount <= 10000))
97101
{
98102
guildListSettings = SettingService.TimeSettingsToGuildRankingSettings(guildListSettings, timeSettings);
99103
guildListSettings.NewSearchValue = artist;
@@ -121,6 +125,7 @@ public async Task GuildTracksAsync(
121125
await RespondAsync(InteractionCallback.DeferredMessage());
122126

123127
var guild = await guildService.GetGuildAsync(this.Context.Guild.Id);
128+
var guildUserCount = await guildService.GetGuildUserCount(this.Context.Guild.Id);
124129

125130
var guildListSettings = new GuildRankingSettings
126131
{
@@ -132,10 +137,11 @@ public async Task GuildTracksAsync(
132137
};
133138

134139
var timeSettings =
135-
SettingService.GetTimePeriod(Enum.GetName(typeof(PlayTimePeriod), timePeriod), TimePeriod.AllTime);
140+
SettingService.GetTimePeriod(Enum.GetName(timePeriod), TimePeriod.AllTime);
136141

137142
if (timeSettings.UsePlays ||
138-
timeSettings.TimePeriod is TimePeriod.AllTime or TimePeriod.Monthly or TimePeriod.Weekly)
143+
timeSettings.TimePeriod is TimePeriod.AllTime or TimePeriod.Weekly ||
144+
(timeSettings.TimePeriod is TimePeriod.Monthly && guildUserCount <= 10000))
139145
{
140146
guildListSettings = SettingService.TimeSettingsToGuildRankingSettings(guildListSettings, timeSettings);
141147
guildListSettings.NewSearchValue = artist;
@@ -160,6 +166,7 @@ public async Task GuildGenresAsync(
160166
await RespondAsync(InteractionCallback.DeferredMessage());
161167

162168
var guild = await guildService.GetGuildAsync(this.Context.Guild.Id);
169+
var guildUserCount = await guildService.GetGuildUserCount(this.Context.Guild.Id);
163170

164171
var guildListSettings = new GuildRankingSettings
165172
{
@@ -170,10 +177,11 @@ public async Task GuildGenresAsync(
170177
};
171178

172179
var timeSettings =
173-
SettingService.GetTimePeriod(Enum.GetName(typeof(PlayTimePeriod), timePeriod), TimePeriod.AllTime);
180+
SettingService.GetTimePeriod(Enum.GetName(timePeriod), TimePeriod.AllTime);
174181

175182
if (timeSettings.UsePlays ||
176-
timeSettings.TimePeriod is TimePeriod.AllTime or TimePeriod.Monthly or TimePeriod.Weekly)
183+
timeSettings.TimePeriod is TimePeriod.AllTime or TimePeriod.Weekly ||
184+
(timeSettings.TimePeriod is TimePeriod.Monthly && guildUserCount <= 10000))
177185
{
178186
guildListSettings = SettingService.TimeSettingsToGuildRankingSettings(guildListSettings, timeSettings);
179187
}

0 commit comments

Comments
 (0)