Release 0.2.0
CI and release / Run tests (push) Failing after 33s
CI and release / Detect release commit (push) Successful in 36s
CI and release / Build and publish container (push) Successful in 6m30s
CI and release / Create release (push) Successful in 15s

This commit is contained in:
Elias Wendland committed 2026-08-25 21:58:43 +02:00
1 parent 97407f7eed
commit 48408cba61
44 files changed
+1874 -514

No files matched your search

+4 -3
View File
@@ -1,5 +1,6 @@
<form method="post" action="$${{action}}">
<input type="hidden" name="search" value="$${{search}}">
$${{additional_fields}} <label>Page <input type="number" name="page" min="1" max="$${{total_pages}}" required></label>
<form method="post" action="{{action}}">
<input type="hidden" name="search" value="{{search}}">
{% if let Some(search_by) = search_by %} <input type="hidden" name="search_by" value="{{search_by}}">
{% endif %} <label>Page <input type="number" name="page" min="1" max="{{total_pages}}" required></label>
<button type="submit">Go</button>
</form>
-1
View File
@@ -1 +0,0 @@
— $${{value}}
+1 -1
View File
@@ -1 +1 @@
<li><a href="/attachments/$${{attachment_id}}?version=$${{message_version}}" target="_blank">View $${{filename}}</a> — $${{size}} bytes$${{content_type}}$${{description}}</li>
<li><a href="/attachments/{{attachment_id}}?version={{message_version}}" target="_blank">View {{filename}}</a> - {{size}} bytes{% if let Some(value) = content_type %} - {{value}}{% endif %}{% if let Some(value) = description %} - {{value}}{% endif %}</li>
+13 -12
View File
@@ -1,22 +1,23 @@
<h2>$${{channel_name}}</h2>
<h2>{{channel_name}}</h2>
<p>You can see this channel because {{access_reason}}.</p>
<dl>
<dt>Channel ID</dt><dd>$${{channel_id}}</dd>
<dt>Server</dt><dd><a href="/servers/$${{server_id}}">$${{server_name}}</a></dd>
<dt>Messages</dt><dd>$${{message_count}}</dd>
<dt>Observed users</dt><dd>$${{user_count}}</dd>
<dt>Message versions</dt><dd>$${{version_count}}</dd>
<dt>Archived data</dt><dd>$${{total_storage}}</dd>
<dt>Message content</dt><dd>$${{message_storage}}</dd>
<dt>Attachments</dt><dd>$${{attachment_storage}}</dd>
<dt>Channel ID</dt><dd>{{channel_id}}</dd>
<dt>Server</dt><dd><a href="/servers/{{server_id}}">{{server_name}}</a></dd>
<dt>Messages</dt><dd>{{message_count}}</dd>
<dt>Observed users</dt><dd>{{user_count}}</dd>
<dt>Message versions</dt><dd>{{version_count}}</dd>
<dt>Archived data</dt><dd>{{total_storage}}</dd>
<dt>Message content</dt><dd>{{message_storage}}</dd>
<dt>Attachments</dt><dd>{{attachment_storage}}</dd>
</dl>
<form method="get" action="/channels/$${{channel_id}}/messages">
<form method="get" action="/channels/{{channel_id}}/messages">
<button type="submit">View messages in this channel</button>
</form>
<h3>Known names</h3>
<ul>
$${{names}}
{{names|safe}}
</ul>
<h3>Observed users</h3>
<ul>
$${{users}}
{{users|safe}}
</ul>
+1 -1
View File
@@ -1 +1 @@
<li><a href="/channels/$${{channel_id}}"><strong>$${{channel_name}}</strong> ($${{channel_id}})</a> in <a href="/servers/$${{server_id}}">$${{server_name}}</a></li>
<li><a href="/channels/{{channel_id}}"><strong>{{channel_name}}</strong> ({{channel_id}})</a> in <a href="/servers/{{server_id}}">{{server_name}}</a></li>
+1 -1
View File
@@ -1 +1 @@
<strong>$${{page_number}}</strong>
<strong>{{page_number}}</strong>
-1
View File
@@ -1 +0,0 @@
<pre>$${{description}}</pre>
-1
View File
@@ -1 +0,0 @@
<strong>$${{title}}</strong>
-1
View File
@@ -1 +0,0 @@
<a href="$${{url}}">$${{url}}</a>
+1 -1
View File
@@ -1 +1 @@
<li>$${{title}}$${{description}}$${{url}}</li>
<li>{% if let Some(value) = title %}<strong>{{value}}</strong>{% endif %}{% if let Some(value) = description %}<pre>{{value}}</pre>{% endif %}{% if let Some(value) = url %}<a href="{{value}}">{{value}}</a>{% endif %}</li>
+1 -1
View File
@@ -1,2 +1,2 @@
<h2>Error</h2>
<p>$${{message}}</p>
<p>{{message}}</p>
+6 -4
View File
@@ -1,8 +1,10 @@
<h2>Archive</h2>
<p>Archived $${{message_count}} messages from $${{user_count}} users across $${{channel_count}} channels on $${{server_count}} servers.</p>
<p>Archived {{message_count}} messages from {{user_count}} users across {{channel_count}} channels on {{server_count}} servers.</p>
<h3>Storage usage</h3>
<dl>
<dt>Total archive</dt><dd>$${{total_storage}}</dd>
<dt>Messages and metadata</dt><dd>$${{message_storage}}</dd>
<dt>Attachments</dt><dd>$${{attachment_storage}}</dd>
<dt>Total archive</dt><dd>{{total_storage}}</dd>
<dt>Messages and metadata</dt><dd>{{message_storage}}</dd>
<dt>Attachments</dt><dd>{{attachment_storage}}</dd>
</dl>
<p>If you cannot see any messages, try and send a message on a server the bot is in.</p>
+5 -5
View File
@@ -1,7 +1,7 @@
<h2>$${{title}}</h2>
$${{search_form}}
<p>$${{item_count}} $${{item_name}} found.</p>
<h2>{{title}}</h2>
{{search_form|safe}}
<p>{{item_count}} {{item_name}} found.</p>
<ul>
$${{items}}
{{items|safe}}
</ul>
$${{pagination}}
{{pagination|safe}}
+6
View File
@@ -0,0 +1,6 @@
<h2>Log in</h2>
<p>It is required to log in with Discord to view the archive.</p>
<p>The login happens on the official Discord website. This site does not have access to your email or password.</p>
<form method="get" action="/login/discord">
<button type="submit">Log in with Discord</button>
</form>
+1 -1
View File
@@ -1 +1 @@
<li><a href="/messages/$${{message_id}}">Message $${{message_id}}</a> by <a href="/users/$${{author_id}}"><strong>$${{author}}</strong></a> in <a href="/servers/$${{server_id}}">$${{server}}</a> / <a href="/channels/$${{channel_id}}">$${{channel}}</a> at $${{timestamp}} — $${{attachment_count}} attachments, $${{embed_count}} embeds</li>
<li><a href="/messages/{{message_id}}">Message {{message_id}}</a> by <a href="/users/{{author_id}}"><strong>{{author}}</strong></a> in <a href="/servers/{{server_id}}">{{server}}</a> / <a href="/channels/{{channel_id}}">{{channel}}</a> at {{timestamp}} - {{attachment_count}} attachments, {{embed_count}} embeds</li>
+5 -5
View File
@@ -1,7 +1,7 @@
<h2>$${{title}}</h2>
$${{search_form}}
<p>$${{item_count}} archived messages found.</p>
<h2>{{title}}</h2>
{{search_form|safe}}
<p>{{item_count}} archived messages found.</p>
<ol>
$${{items}}
{{items|safe}}
</ol>
$${{pagination}}
{{pagination|safe}}
+4 -4
View File
@@ -1,9 +1,9 @@
<form method="post" action="$${{action}}">
<label>Search messages: <input type="search" name="search" value="$${{search}}"></label>
<form method="post" action="{{action}}">
<label>Search messages: <input type="search" name="search" value="{{search}}"></label>
<label>Search by:
<select name="search_by">
<option value="content"$${{content_selected}}>Content</option>
<option value="timestamp"$${{timestamp_selected}}>Timestamp</option>
<option value="content"{{content_selected}}>Content</option>
<option value="timestamp"{{timestamp_selected}}>Timestamp</option>
</select>
</label>
<button type="submit">Search</button>
+2 -2
View File
@@ -1,3 +1,3 @@
<form method="get" action="/messages/$${{message_id}}">
<button type="submit" name="version" value="$${{version}}">$${{label}}</button>
<form method="get" action="/messages/{{message_id}}">
<button type="submit" name="version" value="{{version}}">{{label}}</button>
</form>
+4 -4
View File
@@ -1,9 +1,9 @@
<nav aria-label="Message versions">
<p>Version $${{current_version}} of $${{version_count}} — archived $${{archived_at}}</p>
<p>Version {{current_version}} of {{version_count}} - archived {{archived_at}}</p>
<p>
$${{previous_version}}$${{next_version}} </p>
<form method="get" action="/messages/$${{message_id}}">
<label>Version <input type="number" name="version" min="1" max="$${{version_count}}" value="$${{current_version}}" required></label>
{{previous_version|safe}}{{next_version|safe}} </p>
<form method="get" action="/messages/{{message_id}}">
<label>Version <input type="number" name="version" min="1" max="{{version_count}}" value="{{current_version}}" required></label>
<button type="submit">View version</button>
</form>
</nav>
+10 -9
View File
@@ -1,18 +1,19 @@
<h2>Message $${{message_id}}</h2>
$${{version_navigation}}
<h2>Message {{message_id}}</h2>
<p>You can see this message because {{access_reason}}.</p>
{{version_navigation|safe}}
<dl>
<dt>Author</dt><dd><a href="/users/$${{author_id}}">$${{author}} ($${{author_id}})</a></dd>
<dt>Server</dt><dd><a href="/servers/$${{server_id}}">$${{server}}</a></dd>
<dt>Channel</dt><dd><a href="/channels/$${{channel_id}}">$${{channel}}</a></dd>
<dt>Timestamp</dt><dd>$${{timestamp}}</dd>
<dt>Author</dt><dd><a href="/users/{{author_id}}">{{author}} ({{author_id}})</a></dd>
<dt>Server</dt><dd><a href="/servers/{{server_id}}">{{server}}</a></dd>
<dt>Channel</dt><dd><a href="/channels/{{channel_id}}">{{channel}}</a></dd>
<dt>Timestamp</dt><dd>{{timestamp}}</dd>
</dl>
<h3>Content</h3>
<pre>$${{content}}</pre>
<pre>{{content}}</pre>
<h3>Attachments</h3>
<ul>
$${{attachments}}
{{attachments|safe}}
</ul>
<h3>Embeds</h3>
<ol>
$${{embeds}}
{{embeds|safe}}
</ol>
+4 -3
View File
@@ -1,4 +1,5 @@
<form method="post" action="$${{action}}">
<input type="hidden" name="search" value="$${{search}}">
$${{additional_fields}} <button type="submit" name="page" value="$${{page_number}}">$${{label}}</button>
<form method="post" action="{{action}}">
<input type="hidden" name="search" value="{{search}}">
{% if let Some(search_by) = search_by %} <input type="hidden" name="search_by" value="{{search_by}}">
{% endif %} <button type="submit" name="page" value="{{page_number}}">{{label}}</button>
</form>
+26 -9
View File
@@ -1,23 +1,40 @@
<!doctype html>
<html lang="en">
<html class="theme-{{theme}}" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>$${{title}} — TG Archive</title>
<title>{{ title }} - TG Archive</title>
<link rel="stylesheet" href="/theme.css">
</head>
<body>
<header>
<h1>TG Archive</h1>
<nav>
<header class="site-header">
<strong class="site-brand">TG Archive</strong>
{% if logged_in %} <nav class="site-navigation">
<a href="/">Home</a> |
<a href="/servers">Servers</a> |
<a href="/channels">Channels</a> |
<a href="/users">Users</a> |
<a href="/messages">Messages</a>
</nav>
<a href="/messages">Messages</a> |
<form method="post" action="/logout"><button type="submit">Log out</button></form>
</nav>{% endif %}
</header>
<main>
$${{body}}
<main class="page-content">
{{ body|safe }}
</main>
<footer class="site-footer">
<p class="footer-legal">Source code available <a href="https://git.ewenlau.net/ewenlau/tg-archive-bot">here</a>.<br>
Copyright © 2026 Ewi and contributors<br>
This content is licensed under GPL-3.0.</p>
<form class="footer-theme" method="post" action="/theme">
<label>Theme
<select name="theme">
<option value="white"{% if theme == "white" %} selected{% endif %}>White</option>
<option value="black"{% if theme == "black" %} selected{% endif %}>Black</option>
<option value="oled"{% if theme == "oled" %} selected{% endif %}>OLED</option>
</select>
</label>
<button type="submit">Apply</button>
</form>
</footer>
</body>
</html>
+4 -4
View File
@@ -1,10 +1,10 @@
<nav aria-label="Pages">
<p>
$${{first_pages}}
{{first_pages|safe}}
</p>
$${{arbitrary_page}}
{{arbitrary_page|safe}}
<p>
$${{final_pages}}
{{final_pages|safe}}
</p>
<p>Page $${{current_page}} of $${{total_pages}}</p>
<p>Page {{current_page}} of {{total_pages}}</p>
</nav>
+2 -2
View File
@@ -1,4 +1,4 @@
<form method="post" action="$${{action}}">
<label>$${{label}}: <input type="search" name="search" value="$${{search}}"></label>
<form method="post" action="{{action}}">
<label>{{label}}: <input type="search" name="search" value="{{search}}"></label>
<button type="submit">Search</button>
</form>
+1 -1
View File
@@ -1 +1 @@
— <a href="$${{icon_url}}">icon</a>
- <a href="{{icon_url}}">icon</a>
+14 -14
View File
@@ -1,31 +1,31 @@
<h2>$${{server_name}}</h2>
<h2>{{server_name}}</h2>
<dl>
<dt>Server ID</dt><dd>$${{server_id}}</dd>
<dt>Messages</dt><dd>$${{message_count}}</dd>
<dt>Archived users</dt><dd>$${{user_count}}</dd>
<dt>Archived channels</dt><dd>$${{channel_count}}</dd>
<dt>Message versions</dt><dd>$${{version_count}}</dd>
<dt>Archived data</dt><dd>$${{total_storage}}</dd>
<dt>Message content</dt><dd>$${{message_storage}}</dd>
<dt>Attachments</dt><dd>$${{attachment_storage}}</dd>
<dt>Server ID</dt><dd>{{server_id}}</dd>
<dt>Messages</dt><dd>{{message_count}}</dd>
<dt>Archived users</dt><dd>{{user_count}}</dd>
<dt>Archived channels</dt><dd>{{channel_count}}</dd>
<dt>Message versions</dt><dd>{{version_count}}</dd>
<dt>Archived data</dt><dd>{{total_storage}}</dd>
<dt>Message content</dt><dd>{{message_storage}}</dd>
<dt>Attachments</dt><dd>{{attachment_storage}}</dd>
</dl>
<form method="get" action="/servers/$${{server_id}}/messages">
<form method="get" action="/servers/{{server_id}}/messages">
<button type="submit">View messages in this server</button>
</form>
<h3>Known names</h3>
<ul>
$${{names}}
{{names|safe}}
</ul>
<h3>Known icons</h3>
<ul>
$${{icons}}
{{icons|safe}}
</ul>
<h3>Channels</h3>
<ul>
$${{channels}}
{{channels|safe}}
</ul>
<h3>Observed users</h3>
<p>Users are included after one of their messages is archived in this server.</p>
<ul>
$${{users}}
{{users|safe}}
</ul>
+1 -1
View File
@@ -1 +1 @@
<li><a href="/servers/$${{guild_id}}"><strong>$${{guild_name}}</strong> ($${{guild_id}})</a>$${{icon}}</li>
<li><a href="/servers/{{guild_id}}"><strong>{{guild_name}}</strong> ({{guild_id}})</a>{{icon|safe}}</li>
+1 -1
View File
@@ -1 +1 @@
<li><a href="$${{avatar_url}}"><img src="$${{avatar_url}}" alt="Archived user avatar" width="64" height="64"></a> — first seen $${{first_seen}}, last seen $${{last_seen}}</li>
<li><a href="{{avatar_url}}"><img src="{{avatar_url}}" alt="Archived user avatar" width="64" height="64"></a> - first seen {{first_seen}}, last seen {{last_seen}}</li>
+1 -1
View File
@@ -1 +1 @@
<li><a href="/channels/$${{channel_id}}"><strong>$${{channel_name}}</strong></a> — $${{message_count}} messages</li>
<li><a href="/channels/{{channel_id}}"><strong>{{channel_name}}</strong></a> - {{message_count}} messages</li>
+1 -1
View File
@@ -1 +1 @@
<li><a href="$${{icon_url}}"><img src="$${{icon_url}}" alt="Archived server icon" width="64" height="64"></a> — first seen $${{first_seen}}, last seen $${{last_seen}}</li>
<li><a href="{{icon_url}}"><img src="{{icon_url}}" alt="Archived server icon" width="64" height="64"></a> - first seen {{first_seen}}, last seen {{last_seen}}</li>
+1 -1
View File
@@ -1 +1 @@
<li><strong>$${{name}}</strong> — first seen $${{first_seen}}, last seen $${{last_seen}}</li>
<li><strong>{{name}}</strong> - first seen {{first_seen}}, last seen {{last_seen}}</li>
+1 -1
View File
@@ -1 +1 @@
<li><a href="/servers/$${{server_id}}"><strong>$${{server_name}}</strong></a> — $${{message_count}} messages</li>
<li><a href="/servers/{{server_id}}"><strong>{{server_name}}</strong></a> - {{message_count}} messages</li>
+1 -1
View File
@@ -1 +1 @@
<li><a href="/users/$${{user_id}}"><strong>$${{username}}</strong></a> — $${{message_count}} messages</li>
<li><a href="/users/{{user_id}}"><strong>{{username}}</strong></a> - {{message_count}} messages</li>
+209
View File
@@ -0,0 +1,209 @@
:root {
color-scheme: light;
font-family: Arial, sans-serif;
}
html {
background: #f5f5f5;
color: #202020;
}
html.theme-black {
background: #181818;
color: #e6e6e6;
color-scheme: dark;
}
html.theme-oled {
background: #000;
color: #e6e6e6;
color-scheme: dark;
}
body {
box-sizing: border-box;
display: flex;
flex-direction: column;
line-height: 1.45;
margin: 0 auto;
max-width: 1100px;
min-height: 100vh;
padding: 0 18px;
}
a {
color: #245b91;
}
a:hover {
color: #123f6b;
}
.theme-black a,
.theme-oled a {
color: #8ebbea;
}
.theme-black a:hover,
.theme-oled a:hover {
color: #b8d8f5;
}
.site-header,
.site-footer {
padding: 18px 0;
}
.site-header {
align-items: center;
display: flex;
gap: 24px;
justify-content: space-between;
}
.site-brand {
font-size: 1.2rem;
white-space: nowrap;
}
.site-navigation {
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.site-navigation form {
display: inline;
}
.page-content {
background: #fff;
border: 1px solid #d8d8d8;
flex: 1;
padding: 24px;
}
.theme-black .page-content {
background: #222;
border-color: #444;
}
.theme-oled .page-content {
background: #000;
border-color: #444;
}
button,
input,
select {
border: 1px solid #999;
border-radius: 3px;
box-sizing: border-box;
font: inherit;
padding: 7px;
}
button {
background: #f8f8f8;
color: #202020;
cursor: pointer;
}
button:hover {
background: #e9e9e9;
}
.theme-black button,
.theme-black input,
.theme-black select,
.theme-oled button,
.theme-oled input,
.theme-oled select {
background: #292929;
border-color: #666;
color: #eee;
}
.theme-black button:hover,
.theme-oled button:hover {
background: #3d3d3d;
}
form {
margin: 12px 0;
}
li {
margin: 8px 0;
}
dt {
font-weight: bold;
margin-top: 12px;
}
dd {
margin-left: 0;
}
pre {
overflow-wrap: anywhere;
white-space: pre-wrap;
}
.site-footer {
display: flex;
gap: 24px;
justify-content: space-between;
}
.site-footer > * {
margin: 0;
}
.footer-legal {
text-align: left;
}
.footer-theme {
text-align: right;
}
@media (max-width: 700px) {
body {
padding: 0 10px;
}
.site-header,
.site-footer {
align-items: stretch;
flex-direction: column;
gap: 10px;
padding: 12px 0;
}
.page-content {
padding: 16px;
}
.site-navigation {
line-height: 1.8;
}
.footer-theme {
text-align: left;
}
input,
select {
max-width: 100%;
}
img,
video,
iframe {
height: auto;
max-width: 100%;
}
}
+15 -14
View File
@@ -1,30 +1,31 @@
<h2>$${{username}}</h2>
<h2>{{username}}</h2>
<p>You can see this user because they have messages in a channel where {{access_reason}}.</p>
<dl>
<dt>User ID</dt><dd>$${{user_id}}</dd>
<dt>Messages</dt><dd>$${{message_count}}</dd>
<dt>Servers</dt><dd>$${{server_count}}</dd>
<dt>Channels</dt><dd>$${{channel_count}}</dd>
<dt>Message versions</dt><dd>$${{version_count}}</dd>
<dt>Archived data</dt><dd>$${{total_storage}}</dd>
<dt>Message content</dt><dd>$${{message_storage}}</dd>
<dt>Attachments</dt><dd>$${{attachment_storage}}</dd>
<dt>User ID</dt><dd>{{user_id}}</dd>
<dt>Messages</dt><dd>{{message_count}}</dd>
<dt>Servers</dt><dd>{{server_count}}</dd>
<dt>Channels</dt><dd>{{channel_count}}</dd>
<dt>Message versions</dt><dd>{{version_count}}</dd>
<dt>Archived data</dt><dd>{{total_storage}}</dd>
<dt>Message content</dt><dd>{{message_storage}}</dd>
<dt>Attachments</dt><dd>{{attachment_storage}}</dd>
</dl>
<form method="get" action="/users/$${{user_id}}/messages">
<form method="get" action="/users/{{user_id}}/messages">
<button type="submit">View messages by this user</button>
</form>
<h3>Known usernames</h3>
<ul>
$${{names}}
{{names|safe}}
</ul>
<h3>Known avatars</h3>
<ul>
$${{avatars}}
{{avatars|safe}}
</ul>
<h3>Servers</h3>
<ul>
$${{servers}}
{{servers|safe}}
</ul>
<h3>Channels</h3>
<ul>
$${{channels}}
{{channels|safe}}
</ul>
+1 -1
View File
@@ -1 +1 @@
<li><a href="/users/$${{discord_id}}"><strong>$${{discord_username}}</strong> ($${{discord_id}})</a></li>
<li><a href="/users/{{discord_id}}"><strong>{{discord_username}}</strong> ({{discord_id}})</a></li>