mirror of
https://github.com/chylex/Discord-History-Tracker.git
synced 2025-06-03 17:11:14 +03:00
Store server icons
This commit is contained in:
parent
44b42657ef
commit
312be6609d
@ -142,11 +142,19 @@ const STATE = (function() {
|
||||
if (DISCORD.CHANNEL_TYPE.isPrivate(channelInfo.type)) {
|
||||
server.id = channelInfo.id;
|
||||
server.name = channel.name = getPrivateChannelName(channelInfo);
|
||||
|
||||
if (channelInfo.icon) {
|
||||
server.icon = channelInfo.icon;
|
||||
}
|
||||
}
|
||||
else if (serverInfo) {
|
||||
server.id = serverInfo.id;
|
||||
server.name = serverInfo.name;
|
||||
channel.name = channelInfo.name;
|
||||
|
||||
if (serverInfo.icon) {
|
||||
server.icon = serverInfo.icon;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
|
@ -2,6 +2,7 @@
|
||||
* @name DiscordGuild
|
||||
* @property {String} id
|
||||
* @property {String} name
|
||||
* @property {String|null|undefined} [icon]
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -14,6 +15,7 @@
|
||||
* @property {Number} [position]
|
||||
* @property {String} [topic]
|
||||
* @property {Boolean} [nsfw]
|
||||
* @property {String|null|undefined} [icon]
|
||||
* @property {DiscordUser[]} [rawRecipients]
|
||||
*/
|
||||
|
||||
|
@ -1,7 +1,12 @@
|
||||
using DHT.Server.Download;
|
||||
|
||||
namespace DHT.Server.Data;
|
||||
|
||||
public readonly struct Server {
|
||||
public ulong Id { get; init; }
|
||||
public string Name { get; init; }
|
||||
public ServerType? Type { get; init; }
|
||||
public string? IconHash { get; init; }
|
||||
|
||||
internal FileUrl? IconUrl => Type == null || IconHash == null ? null : DownloadLinkExtractor.ServerIcon(Type.Value, Id, IconHash);
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ static class ViewerJson {
|
||||
public sealed class JsonServer {
|
||||
public required string Name { get; init; }
|
||||
public required string Type { get; init; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? IconUrl { get; init; }
|
||||
}
|
||||
|
||||
public sealed class JsonChannel {
|
||||
|
@ -108,6 +108,7 @@ static class ViewerJsonExport {
|
||||
servers[server.Id] = new ViewerJson.JsonServer {
|
||||
Name = server.Name,
|
||||
Type = ServerTypes.ToJsonViewerString(server.Type),
|
||||
IconUrl = server.IconUrl?.DownloadUrl,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -394,16 +394,6 @@ sealed class SqliteDownloadRepository(SqliteConnectionPool pool) : BaseSqliteRep
|
||||
}
|
||||
}
|
||||
|
||||
await using (var cmd = conn.Command("SELECT id, avatar_url FROM users WHERE avatar_url IS NOT NULL")) {
|
||||
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
|
||||
|
||||
while (await reader.ReadAsync(cancellationToken)) {
|
||||
ulong id = reader.GetUint64(0);
|
||||
string avatarHash = reader.GetString(1);
|
||||
yield return DownloadLinkExtractor.UserAvatar(id, avatarHash);
|
||||
}
|
||||
}
|
||||
|
||||
await using (var cmd = conn.Command("SELECT DISTINCT emoji_id, emoji_flags FROM message_reactions WHERE emoji_id IS NOT NULL")) {
|
||||
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
|
||||
|
||||
@ -413,5 +403,29 @@ sealed class SqliteDownloadRepository(SqliteConnectionPool pool) : BaseSqliteRep
|
||||
yield return DownloadLinkExtractor.Emoji(emojiId, emojiFlags);
|
||||
}
|
||||
}
|
||||
|
||||
await using (var cmd = conn.Command("SELECT id, type, icon_hash FROM servers WHERE icon_hash IS NOT NULL")) {
|
||||
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
|
||||
|
||||
while (await reader.ReadAsync(cancellationToken)) {
|
||||
ulong id = reader.GetUint64(0);
|
||||
ServerType? type = ServerTypes.FromString(reader.GetString(1));
|
||||
string iconHash = reader.GetString(2);
|
||||
|
||||
if (DownloadLinkExtractor.ServerIcon(type, id, iconHash) is {} result) {
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await using (var cmd = conn.Command("SELECT id, avatar_url FROM users WHERE avatar_url IS NOT NULL")) {
|
||||
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
|
||||
|
||||
while (await reader.ReadAsync(cancellationToken)) {
|
||||
ulong id = reader.GetUint64(0);
|
||||
string avatarHash = reader.GetString(1);
|
||||
yield return DownloadLinkExtractor.UserAvatar(id, avatarHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,15 +10,9 @@ using Microsoft.Data.Sqlite;
|
||||
|
||||
namespace DHT.Server.Database.Sqlite.Repositories;
|
||||
|
||||
sealed class SqliteServerRepository : BaseSqliteRepository, IServerRepository {
|
||||
sealed class SqliteServerRepository(SqliteConnectionPool pool, SqliteDownloadRepository downloads) : BaseSqliteRepository(Log), IServerRepository {
|
||||
private static readonly Log Log = Log.ForType<SqliteServerRepository>();
|
||||
|
||||
private readonly SqliteConnectionPool pool;
|
||||
|
||||
public SqliteServerRepository(SqliteConnectionPool pool) : base(Log) {
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
public async Task Add(IReadOnlyList<Data.Server> servers) {
|
||||
await using (var conn = await pool.Take()) {
|
||||
await conn.BeginTransactionAsync();
|
||||
@ -27,13 +21,18 @@ sealed class SqliteServerRepository : BaseSqliteRepository, IServerRepository {
|
||||
("id", SqliteType.Integer),
|
||||
("name", SqliteType.Text),
|
||||
("type", SqliteType.Text),
|
||||
("icon_hash", SqliteType.Text),
|
||||
]);
|
||||
|
||||
await using var downloadCollector = new SqliteDownloadRepository.NewDownloadCollector(downloads, conn);
|
||||
|
||||
foreach (Data.Server server in servers) {
|
||||
cmd.Set(":id", server.Id);
|
||||
cmd.Set(":name", server.Name);
|
||||
cmd.Set(":type", ServerTypes.ToString(server.Type));
|
||||
cmd.Set(":icon_hash", server.IconHash);
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
await downloadCollector.AddIfNotNull(server.IconUrl?.ToPendingDownload());
|
||||
}
|
||||
|
||||
await conn.CommitTransactionAsync();
|
||||
@ -50,7 +49,7 @@ sealed class SqliteServerRepository : BaseSqliteRepository, IServerRepository {
|
||||
public async IAsyncEnumerable<Data.Server> Get([EnumeratorCancellation] CancellationToken cancellationToken) {
|
||||
await using var conn = await pool.Take();
|
||||
|
||||
await using var cmd = conn.Command("SELECT id, name, type FROM servers");
|
||||
await using var cmd = conn.Command("SELECT id, name, type, icon_hash FROM servers");
|
||||
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
|
||||
|
||||
while (await reader.ReadAsync(cancellationToken)) {
|
||||
@ -58,6 +57,7 @@ sealed class SqliteServerRepository : BaseSqliteRepository, IServerRepository {
|
||||
Id = reader.GetUint64(0),
|
||||
Name = reader.GetString(1),
|
||||
Type = ServerTypes.FromString(reader.GetString(2)),
|
||||
IconHash = reader.IsDBNull(3) ? null : reader.GetString(3),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
11
app/Server/Database/Sqlite/Schema/SqliteSchemaUpgradeTo11.cs
Normal file
11
app/Server/Database/Sqlite/Schema/SqliteSchemaUpgradeTo11.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
using DHT.Server.Database.Sqlite.Utils;
|
||||
|
||||
namespace DHT.Server.Database.Sqlite.Schema;
|
||||
|
||||
sealed class SqliteSchemaUpgradeTo11 : ISchemaUpgrade {
|
||||
async Task ISchemaUpgrade.Run(ISqliteConnection conn, ISchemaUpgradeCallbacks.IProgressReporter reporter) {
|
||||
await reporter.MainWork("Applying schema changes...", finishedItems: 0, totalItems: 1);
|
||||
await conn.ExecuteAsync("ALTER TABLE servers ADD icon_hash TEXT");
|
||||
}
|
||||
}
|
@ -66,16 +66,16 @@ public sealed class SqliteDatabaseFile : IDatabaseFile {
|
||||
downloads = new SqliteDownloadRepository(pool);
|
||||
settings = new SqliteSettingsRepository(pool);
|
||||
users = new SqliteUserRepository(pool, downloads);
|
||||
servers = new SqliteServerRepository(pool);
|
||||
servers = new SqliteServerRepository(pool, downloads);
|
||||
channels = new SqliteChannelRepository(pool);
|
||||
messages = new SqliteMessageRepository(pool, downloads);
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync() {
|
||||
users.Dispose();
|
||||
servers.Dispose();
|
||||
channels.Dispose();
|
||||
messages.Dispose();
|
||||
channels.Dispose();
|
||||
servers.Dispose();
|
||||
users.Dispose();
|
||||
downloads.Dispose();
|
||||
await pool.DisposeAsync();
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ using Microsoft.Data.Sqlite;
|
||||
namespace DHT.Server.Database.Sqlite;
|
||||
|
||||
sealed class SqliteSchema(CustomSqliteConnection conn) {
|
||||
internal const int Version = 10;
|
||||
internal const int Version = 11;
|
||||
|
||||
private static readonly Log Log = Log.ForType<SqliteSchema>();
|
||||
|
||||
@ -92,9 +92,10 @@ sealed class SqliteSchema(CustomSqliteConnection conn) {
|
||||
|
||||
await conn.ExecuteAsync("""
|
||||
CREATE TABLE servers (
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
icon_hash TEXT
|
||||
)
|
||||
""");
|
||||
|
||||
@ -222,6 +223,7 @@ sealed class SqliteSchema(CustomSqliteConnection conn) {
|
||||
{ 7, new SqliteSchemaUpgradeTo8() },
|
||||
{ 8, new SqliteSchemaUpgradeTo9() },
|
||||
{ 9, new SqliteSchemaUpgradeTo10() },
|
||||
{ 10, new SqliteSchemaUpgradeTo11() },
|
||||
};
|
||||
|
||||
Perf perf = Log.Start("from version " + dbVersion);
|
||||
|
@ -12,6 +12,14 @@ namespace DHT.Server.Download;
|
||||
static class DownloadLinkExtractor {
|
||||
private static readonly Log Log = Log.ForType(typeof(DownloadLinkExtractor));
|
||||
|
||||
public static FileUrl? ServerIcon(ServerType? type, ulong id, string iconHash) {
|
||||
return type switch {
|
||||
ServerType.Server => new FileUrl($"https://cdn.discordapp.com/icons/{id}/{iconHash}.webp", MediaTypeNames.Image.Webp),
|
||||
ServerType.Group => new FileUrl($"https://cdn.discordapp.com/channel-icons/{id}/{iconHash}.webp", MediaTypeNames.Image.Webp),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
public static FileUrl UserAvatar(ulong id, string avatarHash) {
|
||||
return new FileUrl($"https://cdn.discordapp.com/avatars/{id}/{avatarHash}.webp", MediaTypeNames.Image.Webp);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ sealed class TrackChannelEndpoint(IDatabaseFile db) : BaseEndpoint {
|
||||
Id = json.RequireSnowflake("id", path),
|
||||
Name = json.RequireString("name", path),
|
||||
Type = ServerTypes.FromString(json.RequireString("type", path)) ?? throw new HttpException(HttpStatusCode.BadRequest, "Server type must be either 'SERVER', 'GROUP', or 'DM'."),
|
||||
IconHash = json.HasKey("icon") ? json.RequireString("icon", path) : null,
|
||||
};
|
||||
}
|
||||
|
||||
|
BIN
app/empty.dht
BIN
app/empty.dht
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user