mirror of
https://github.com/chylex/Discord-History-Tracker.git
synced 2025-04-14 07:37:13 +03:00
Update viewer to reference downloaded embeds, avatars, and emoji
This commit is contained in:
parent
7173dc6cfc
commit
72b8fb7c14
@ -18,7 +18,6 @@ using DHT.Desktop.Server;
|
|||||||
using DHT.Server;
|
using DHT.Server;
|
||||||
using DHT.Server.Data.Filters;
|
using DHT.Server.Data.Filters;
|
||||||
using DHT.Server.Database.Export;
|
using DHT.Server.Database.Export;
|
||||||
using DHT.Server.Database.Export.Strategy;
|
|
||||||
using static DHT.Desktop.Program;
|
using static DHT.Desktop.Program;
|
||||||
|
|
||||||
namespace DHT.Desktop.Main.Pages;
|
namespace DHT.Desktop.Main.Pages;
|
||||||
@ -63,9 +62,13 @@ sealed partial class ViewerPageModel : ObservableObject, IDisposable {
|
|||||||
public async void OnClickOpenViewer() {
|
public async void OnClickOpenViewer() {
|
||||||
try {
|
try {
|
||||||
var fullPath = await PrepareTemporaryViewerFile();
|
var fullPath = await PrepareTemporaryViewerFile();
|
||||||
var strategy = new LiveViewerExportStrategy(ServerConfiguration.Port, ServerConfiguration.Token);
|
|
||||||
|
string jsConstants = $"""
|
||||||
|
window.DHT_SERVER_URL = "{HttpUtility.JavaScriptStringEncode("http://127.0.0.1:" + ServerConfiguration.Port)}";
|
||||||
|
window.DHT_SERVER_TOKEN = "{HttpUtility.JavaScriptStringEncode(ServerConfiguration.Token)}";
|
||||||
|
""";
|
||||||
|
|
||||||
await ProgressDialog.ShowIndeterminate(window, "Open Viewer", "Creating viewer...", _ => Task.Run(() => WriteViewerFile(fullPath, strategy)));
|
await ProgressDialog.ShowIndeterminate(window, "Open Viewer", "Creating viewer...", _ => Task.Run(() => WriteViewerFile(fullPath, jsConstants)));
|
||||||
|
|
||||||
Process.Start(new ProcessStartInfo(fullPath) {
|
Process.Start(new ProcessStartInfo(fullPath) {
|
||||||
UseShellExecute = true
|
UseShellExecute = true
|
||||||
@ -109,17 +112,18 @@ sealed partial class ViewerPageModel : ObservableObject, IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ProgressDialog.ShowIndeterminate(window, "Save Viewer", "Creating viewer...", _ => Task.Run(() => WriteViewerFile(path, StandaloneViewerExportStrategy.Instance)));
|
await ProgressDialog.ShowIndeterminate(window, "Save Viewer", "Creating viewer...", _ => Task.Run(() => WriteViewerFile(path, string.Empty)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
await Dialog.ShowOk(window, "Save Viewer", "Could not create or save viewer: " + e.Message);
|
await Dialog.ShowOk(window, "Save Viewer", "Could not create or save viewer: " + e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WriteViewerFile(string path, IViewerExportStrategy strategy) {
|
private async Task WriteViewerFile(string path, string jsConstants) {
|
||||||
const string ArchiveTag = "/*[ARCHIVE]*/";
|
const string ArchiveTag = "/*[ARCHIVE]*/";
|
||||||
|
|
||||||
string indexFile = await Resources.ReadTextAsync("Viewer/index.html");
|
string indexFile = await Resources.ReadTextAsync("Viewer/index.html");
|
||||||
string viewerTemplate = indexFile.Replace("/*[JS]*/", await Resources.ReadJoinedAsync("Viewer/scripts/", '\n'))
|
string viewerTemplate = indexFile.Replace("/*[CONSTANTS]*/", jsConstants)
|
||||||
|
.Replace("/*[JS]*/", await Resources.ReadJoinedAsync("Viewer/scripts/", '\n'))
|
||||||
.Replace("/*[CSS]*/", await Resources.ReadJoinedAsync("Viewer/styles/", '\n'));
|
.Replace("/*[CSS]*/", await Resources.ReadJoinedAsync("Viewer/styles/", '\n'));
|
||||||
|
|
||||||
int viewerArchiveTagStart = viewerTemplate.IndexOf(ArchiveTag);
|
int viewerArchiveTagStart = viewerTemplate.IndexOf(ArchiveTag);
|
||||||
@ -128,7 +132,7 @@ sealed partial class ViewerPageModel : ObservableObject, IDisposable {
|
|||||||
string jsonTempFile = path + ".tmp";
|
string jsonTempFile = path + ".tmp";
|
||||||
|
|
||||||
await using (var jsonStream = new FileStream(jsonTempFile, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) {
|
await using (var jsonStream = new FileStream(jsonTempFile, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) {
|
||||||
await ViewerJsonExport.Generate(jsonStream, strategy, state.Db, FilterModel.CreateFilter());
|
await ViewerJsonExport.Generate(jsonStream, state.Db, FilterModel.CreateFilter());
|
||||||
|
|
||||||
char[] jsonBuffer = new char[Math.Min(32768, jsonStream.Position)];
|
char[] jsonBuffer = new char[Math.Min(32768, jsonStream.Position)];
|
||||||
jsonStream.Position = 0;
|
jsonStream.Position = 0;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.DHT_EMBEDDED = "/*[ARCHIVE]*/";
|
window.DHT_EMBEDDED = "/*[ARCHIVE]*/";
|
||||||
|
/*[CONSTANTS]*/
|
||||||
/*[JS]*/
|
/*[JS]*/
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
@ -35,6 +35,23 @@ const DISCORD = (function() {
|
|||||||
let templateReaction;
|
let templateReaction;
|
||||||
let templateReactionCustom;
|
let templateReactionCustom;
|
||||||
|
|
||||||
|
const fileUrlProcessor = function(serverUrl, serverToken) {
|
||||||
|
if (typeof serverUrl === "string" && typeof serverToken === "string") {
|
||||||
|
return url => serverUrl + "/get-downloaded-file/" + encodeURIComponent(url) + "?token=" + encodeURIComponent(serverToken);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return url => url;
|
||||||
|
}
|
||||||
|
}(
|
||||||
|
window["DHT_SERVER_URL"],
|
||||||
|
window["DHT_SERVER_TOKEN"]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getEmoji = function(name, id, extension) {
|
||||||
|
const tag = ":" + name + ":";
|
||||||
|
return "<img src='" + fileUrlProcessor("https://cdn.discordapp.com/emojis/" + id + "." + extension) + "' alt='" + tag + "' title='" + tag + "' class='emoji'>";
|
||||||
|
};
|
||||||
|
|
||||||
const processMessageContents = function(contents) {
|
const processMessageContents = function(contents) {
|
||||||
let processed = DOM.escapeHTML(contents.replace(regex.formatUrlNoEmbed, "$1"));
|
let processed = DOM.escapeHTML(contents.replace(regex.formatUrlNoEmbed, "$1"));
|
||||||
|
|
||||||
@ -54,29 +71,33 @@ const DISCORD = (function() {
|
|||||||
.replace(regex.formatStrike, "<s>$1</s>");
|
.replace(regex.formatStrike, "<s>$1</s>");
|
||||||
}
|
}
|
||||||
|
|
||||||
const animatedEmojiExtension = SETTINGS.enableAnimatedEmoji ? "gif" : "png";
|
const animatedEmojiExtension = SETTINGS.enableAnimatedEmoji ? "gif" : "webp";
|
||||||
|
|
||||||
// noinspection HtmlUnknownTarget
|
// noinspection HtmlUnknownTarget
|
||||||
processed = processed
|
processed = processed
|
||||||
.replace(regex.formatUrl, "<a href='$1' target='_blank' rel='noreferrer'>$1</a>")
|
.replace(regex.formatUrl, "<a href='$1' target='_blank' rel='noreferrer'>$1</a>")
|
||||||
.replace(regex.mentionChannel, (full, match) => "<span class='link mention-chat'>#" + STATE.getChannelName(match) + "</span>")
|
.replace(regex.mentionChannel, (full, match) => "<span class='link mention-chat'>#" + STATE.getChannelName(match) + "</span>")
|
||||||
.replace(regex.mentionUser, (full, match) => "<span class='link mention-user' title='#" + (STATE.getUserTag(match) || "????") + "'>@" + STATE.getUserName(match) + "</span>")
|
.replace(regex.mentionUser, (full, match) => "<span class='link mention-user' title='#" + (STATE.getUserTag(match) || "????") + "'>@" + STATE.getUserName(match) + "</span>")
|
||||||
.replace(regex.customEmojiStatic, "<img src='https://cdn.discordapp.com/emojis/$2.png' alt=':$1:' title=':$1:' class='emoji'>")
|
.replace(regex.customEmojiStatic, (full, m1, m2) => getEmoji(m1, m2, "webp"))
|
||||||
.replace(regex.customEmojiAnimated, "<img src='https://cdn.discordapp.com/emojis/$2." + animatedEmojiExtension + "' alt=':$1:' title=':$1:' class='emoji'>");
|
.replace(regex.customEmojiAnimated, (full, m1, m2) => getEmoji(m1, m2, animatedEmojiExtension));
|
||||||
|
|
||||||
return "<p>" + processed + "</p>";
|
return "<p>" + processed + "</p>";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAvatarUrlObject = function(avatar) {
|
||||||
|
return { url: fileUrlProcessor("https://cdn.discordapp.com/avatars/" + avatar.id + "/" + avatar.path + ".webp") };
|
||||||
|
};
|
||||||
|
|
||||||
const getImageEmbed = function(url, image) {
|
const getImageEmbed = function(url, image) {
|
||||||
if (!SETTINGS.enableImagePreviews) {
|
if (!SETTINGS.enableImagePreviews) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image.width && image.height) {
|
if (image.width && image.height) {
|
||||||
return templateEmbedImageWithSize.apply({ url, src: image.url, width: image.width, height: image.height });
|
return templateEmbedImageWithSize.apply({ url: fileUrlProcessor(url), src: fileUrlProcessor(image.url), width: image.width, height: image.height });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return templateEmbedImage.apply({ url, src: image.url });
|
return templateEmbedImage.apply({ url: fileUrlProcessor(url), src: fileUrlProcessor(image.url) });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -125,8 +146,9 @@ const DISCORD = (function() {
|
|||||||
"</div>"
|
"</div>"
|
||||||
].join(""));
|
].join(""));
|
||||||
|
|
||||||
|
// noinspection HtmlUnknownTarget
|
||||||
templateUserAvatar = new TEMPLATE([
|
templateUserAvatar = new TEMPLATE([
|
||||||
"<img src='https://cdn.discordapp.com/avatars/{id}/{path}.webp?size=128' alt=''>"
|
"<img src='{url}' alt=''>"
|
||||||
].join(""));
|
].join(""));
|
||||||
|
|
||||||
// noinspection HtmlUnknownTarget
|
// noinspection HtmlUnknownTarget
|
||||||
@ -167,8 +189,9 @@ const DISCORD = (function() {
|
|||||||
"<span class='reaction-wrapper'><span class='reaction-emoji'>{n}</span><span class='count'>{c}</span></span>"
|
"<span class='reaction-wrapper'><span class='reaction-emoji'>{n}</span><span class='count'>{c}</span></span>"
|
||||||
].join(""));
|
].join(""));
|
||||||
|
|
||||||
|
// noinspection HtmlUnknownTarget
|
||||||
templateReactionCustom = new TEMPLATE([
|
templateReactionCustom = new TEMPLATE([
|
||||||
"<span class='reaction-wrapper'><img src='https://cdn.discordapp.com/emojis/{id}.{ext}' alt=':{n}:' title=':{n}:' class='reaction-emoji-custom'><span class='count'>{c}</span></span>"
|
"<span class='reaction-wrapper'><img src='{url}' alt=':{n}:' title=':{n}:' class='reaction-emoji-custom'><span class='count'>{c}</span></span>"
|
||||||
].join(""));
|
].join(""));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -199,7 +222,7 @@ const DISCORD = (function() {
|
|||||||
getMessageHTML(message) { // noinspection FunctionWithInconsistentReturnsJS
|
getMessageHTML(message) { // noinspection FunctionWithInconsistentReturnsJS
|
||||||
return (SETTINGS.enableUserAvatars ? templateMessageWithAvatar : templateMessageNoAvatar).apply(message, (property, value) => {
|
return (SETTINGS.enableUserAvatars ? templateMessageWithAvatar : templateMessageNoAvatar).apply(message, (property, value) => {
|
||||||
if (property === "avatar") {
|
if (property === "avatar") {
|
||||||
return value ? templateUserAvatar.apply(value) : "";
|
return value ? templateUserAvatar.apply(getAvatarUrlObject(value)) : "";
|
||||||
}
|
}
|
||||||
else if (property === "user.tag") {
|
else if (property === "user.tag") {
|
||||||
return value ? value : "????";
|
return value ? value : "????";
|
||||||
@ -220,10 +243,10 @@ const DISCORD = (function() {
|
|||||||
return templateEmbedUnsupported.apply(embed);
|
return templateEmbedUnsupported.apply(embed);
|
||||||
}
|
}
|
||||||
else if ("image" in embed && embed.image.url) {
|
else if ("image" in embed && embed.image.url) {
|
||||||
return getImageEmbed(embed.url, embed.image);
|
return getImageEmbed(fileUrlProcessor(embed.url), embed.image);
|
||||||
}
|
}
|
||||||
else if ("thumbnail" in embed && embed.thumbnail.url) {
|
else if ("thumbnail" in embed && embed.thumbnail.url) {
|
||||||
return getImageEmbed(embed.url, embed.thumbnail);
|
return getImageEmbed(fileUrlProcessor(embed.url), embed.thumbnail);
|
||||||
}
|
}
|
||||||
else if ("title" in embed && "description" in embed) {
|
else if ("title" in embed && "description" in embed) {
|
||||||
return templateEmbedRich.apply(embed);
|
return templateEmbedRich.apply(embed);
|
||||||
@ -242,14 +265,16 @@ const DISCORD = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return value.map(attachment => {
|
return value.map(attachment => {
|
||||||
|
const url = fileUrlProcessor(attachment.url);
|
||||||
|
|
||||||
if (!DISCORD.isImageAttachment(attachment) || !SETTINGS.enableImagePreviews) {
|
if (!DISCORD.isImageAttachment(attachment) || !SETTINGS.enableImagePreviews) {
|
||||||
return templateAttachmentDownload.apply(attachment);
|
return templateAttachmentDownload.apply({ url, name: attachment.name });
|
||||||
}
|
}
|
||||||
else if ("width" in attachment && "height" in attachment) {
|
else if ("width" in attachment && "height" in attachment) {
|
||||||
return templateEmbedImageWithSize.apply({ url: attachment.url, src: attachment.url, width: attachment.width, height: attachment.height });
|
return templateEmbedImageWithSize.apply({ url, src: url, width: attachment.width, height: attachment.height });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return templateEmbedImage.apply({ url: attachment.url, src: attachment.url });
|
return templateEmbedImage.apply({ url, src: url });
|
||||||
}
|
}
|
||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
@ -265,7 +290,7 @@ const DISCORD = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const user = "<span class='reply-username' title='#" + (value.user.tag ? value.user.tag : "????") + "'>" + value.user.name + "</span>";
|
const user = "<span class='reply-username' title='#" + (value.user.tag ? value.user.tag : "????") + "'>" + value.user.name + "</span>";
|
||||||
const avatar = SETTINGS.enableUserAvatars && value.avatar ? "<span class='reply-avatar'>" + templateUserAvatar.apply(value.avatar) + "</span>" : "";
|
const avatar = SETTINGS.enableUserAvatars && value.avatar ? "<span class='reply-avatar'>" + templateUserAvatar.apply(getAvatarUrlObject(value.avatar)) + "</span>" : "";
|
||||||
const contents = value.contents ? "<span class='reply-contents'>" + processMessageContents(value.contents) + "</span>" : "";
|
const contents = value.contents ? "<span class='reply-contents'>" + processMessageContents(value.contents) + "</span>" : "";
|
||||||
|
|
||||||
return "<span class='jump' data-jump='" + value.id + "'>Jump to reply</span><span class='user'>" + avatar + user + "</span>" + contents;
|
return "<span class='jump' data-jump='" + value.id + "'>Jump to reply</span><span class='user'>" + avatar + user + "</span>" + contents;
|
||||||
@ -277,9 +302,10 @@ const DISCORD = (function() {
|
|||||||
|
|
||||||
return "<div class='reactions'>" + value.map(reaction => {
|
return "<div class='reactions'>" + value.map(reaction => {
|
||||||
if ("id" in reaction){
|
if ("id" in reaction){
|
||||||
// noinspection JSUnusedGlobalSymbols, JSUnresolvedVariable
|
const ext = reaction.a && SETTINGS.enableAnimatedEmoji ? "gif" : "webp";
|
||||||
reaction.ext = reaction.a && SETTINGS.enableAnimatedEmoji ? "gif" : "png";
|
const url = fileUrlProcessor("https://cdn.discordapp.com/emojis/" + reaction.id + "." + ext);
|
||||||
return templateReactionCustom.apply(reaction);
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
return templateReactionCustom.apply({ url, n: reaction.n, c: reaction.c });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return templateReaction.apply(reaction);
|
return templateReaction.apply(reaction);
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
using DHT.Server.Data;
|
|
||||||
|
|
||||||
namespace DHT.Server.Database.Export.Strategy;
|
|
||||||
|
|
||||||
public interface IViewerExportStrategy {
|
|
||||||
string GetAttachmentUrl(Attachment attachment);
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
using System.Net;
|
|
||||||
using DHT.Server.Data;
|
|
||||||
|
|
||||||
namespace DHT.Server.Database.Export.Strategy;
|
|
||||||
|
|
||||||
public sealed class LiveViewerExportStrategy : IViewerExportStrategy {
|
|
||||||
private readonly string safePort;
|
|
||||||
private readonly string safeToken;
|
|
||||||
|
|
||||||
public LiveViewerExportStrategy(ushort port, string token) {
|
|
||||||
this.safePort = port.ToString();
|
|
||||||
this.safeToken = WebUtility.UrlEncode(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetAttachmentUrl(Attachment attachment) {
|
|
||||||
return "http://127.0.0.1:" + safePort + "/get-downloaded-file/" + WebUtility.UrlEncode(attachment.NormalizedUrl) + "?token=" + safeToken;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
using DHT.Server.Data;
|
|
||||||
|
|
||||||
namespace DHT.Server.Database.Export.Strategy;
|
|
||||||
|
|
||||||
public sealed class StandaloneViewerExportStrategy : IViewerExportStrategy {
|
|
||||||
public static StandaloneViewerExportStrategy Instance { get; } = new ();
|
|
||||||
|
|
||||||
private StandaloneViewerExportStrategy() {}
|
|
||||||
|
|
||||||
public string GetAttachmentUrl(Attachment attachment) {
|
|
||||||
// The normalized URL will not load files from Discord CDN once the time limit is enforced.
|
|
||||||
|
|
||||||
// The downloaded URL would work, but only for a limited time, so it is better for the links to not work
|
|
||||||
// rather than give users a false sense of security.
|
|
||||||
|
|
||||||
return attachment.NormalizedUrl;
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ using System.Text.Json;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DHT.Server.Data;
|
using DHT.Server.Data;
|
||||||
using DHT.Server.Data.Filters;
|
using DHT.Server.Data.Filters;
|
||||||
using DHT.Server.Database.Export.Strategy;
|
|
||||||
using DHT.Utils.Logging;
|
using DHT.Utils.Logging;
|
||||||
|
|
||||||
namespace DHT.Server.Database.Export;
|
namespace DHT.Server.Database.Export;
|
||||||
@ -14,7 +13,7 @@ namespace DHT.Server.Database.Export;
|
|||||||
public static class ViewerJsonExport {
|
public static class ViewerJsonExport {
|
||||||
private static readonly Log Log = Log.ForType(typeof(ViewerJsonExport));
|
private static readonly Log Log = Log.ForType(typeof(ViewerJsonExport));
|
||||||
|
|
||||||
public static async Task Generate(Stream stream, IViewerExportStrategy strategy, IDatabaseFile db, MessageFilter? filter = null) {
|
public static async Task Generate(Stream stream, IDatabaseFile db, MessageFilter? filter = null) {
|
||||||
var perf = Log.Start();
|
var perf = Log.Start();
|
||||||
|
|
||||||
var includedUserIds = new HashSet<ulong>();
|
var includedUserIds = new HashSet<ulong>();
|
||||||
@ -49,7 +48,7 @@ public static class ViewerJsonExport {
|
|||||||
Servers = servers,
|
Servers = servers,
|
||||||
Channels = channels
|
Channels = channels
|
||||||
},
|
},
|
||||||
Data = GenerateMessageList(includedMessages, userIndices, strategy)
|
Data = GenerateMessageList(includedMessages, userIndices)
|
||||||
};
|
};
|
||||||
|
|
||||||
perf.Step("Generate value object");
|
perf.Step("Generate value object");
|
||||||
@ -125,7 +124,7 @@ public static class ViewerJsonExport {
|
|||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<Snowflake, Dictionary<Snowflake, ViewerJson.JsonMessage>> GenerateMessageList(List<Message> includedMessages, Dictionary<ulong, int> userIndices, IViewerExportStrategy strategy) {
|
private static Dictionary<Snowflake, Dictionary<Snowflake, ViewerJson.JsonMessage>> GenerateMessageList(List<Message> includedMessages, Dictionary<ulong, int> userIndices) {
|
||||||
var data = new Dictionary<Snowflake, Dictionary<Snowflake, ViewerJson.JsonMessage>>();
|
var data = new Dictionary<Snowflake, Dictionary<Snowflake, ViewerJson.JsonMessage>>();
|
||||||
|
|
||||||
foreach (var grouping in includedMessages.GroupBy(static message => message.Channel)) {
|
foreach (var grouping in includedMessages.GroupBy(static message => message.Channel)) {
|
||||||
@ -142,9 +141,9 @@ public static class ViewerJsonExport {
|
|||||||
Te = message.EditTimestamp,
|
Te = message.EditTimestamp,
|
||||||
R = message.RepliedToId?.ToString(),
|
R = message.RepliedToId?.ToString(),
|
||||||
|
|
||||||
A = message.Attachments.IsEmpty ? null : message.Attachments.Select(attachment => {
|
A = message.Attachments.IsEmpty ? null : message.Attachments.Select(static attachment => {
|
||||||
var a = new ViewerJson.JsonMessageAttachment {
|
var a = new ViewerJson.JsonMessageAttachment {
|
||||||
Url = strategy.GetAttachmentUrl(attachment),
|
Url = attachment.DownloadUrl,
|
||||||
Name = Uri.TryCreate(attachment.NormalizedUrl, UriKind.Absolute, out var uri) ? Path.GetFileName(uri.LocalPath) : attachment.NormalizedUrl
|
Name = Uri.TryCreate(attachment.NormalizedUrl, UriKind.Absolute, out var uri) ? Path.GetFileName(uri.LocalPath) : attachment.NormalizedUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DHT.Server.Data;
|
|
||||||
using DHT.Server.Database;
|
using DHT.Server.Database;
|
||||||
|
using DHT.Server.Download;
|
||||||
using DHT.Utils.Http;
|
using DHT.Utils.Http;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
@ -11,14 +11,14 @@ sealed class GetDownloadedFileEndpoint : BaseEndpoint {
|
|||||||
public GetDownloadedFileEndpoint(IDatabaseFile db) : base(db) {}
|
public GetDownloadedFileEndpoint(IDatabaseFile db) : base(db) {}
|
||||||
|
|
||||||
protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
|
protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
|
||||||
string normalizedUrl = WebUtility.UrlDecode((string) ctx.Request.RouteValues["url"]!);
|
string url = WebUtility.UrlDecode((string) ctx.Request.RouteValues["url"]!);
|
||||||
DownloadWithData? maybeDownloadWithData = await Db.Downloads.GetSuccessfulDownloadWithData(normalizedUrl);
|
string normalizedUrl = DiscordCdn.NormalizeUrl(url);
|
||||||
|
|
||||||
if (maybeDownloadWithData is { Download: {} download, Data: {} data }) {
|
if (await Db.Downloads.GetSuccessfulDownloadWithData(normalizedUrl) is { Download: {} download, Data: {} data }) {
|
||||||
return new HttpOutput.File(download.Type, data);
|
return new HttpOutput.File(download.Type, data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new HttpOutput.Redirect(normalizedUrl, permanent: false);
|
return new HttpOutput.Redirect(url, permanent: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user