diff --git a/media/channel/13.svg b/media/channel/13.svg
new file mode 100644
index 0000000..aad9219
--- /dev/null
+++ b/media/channel/13.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/media/script.js b/media/script.js
index 19d3783..db61696 100644
--- a/media/script.js
+++ b/media/script.js
@@ -32,30 +32,70 @@ function proxyFetch(url, o) {
body: JSON.stringify(opts)
})
}
-function parseMD(text) {
- return text
+function parseMD(text, extended=true) {
+ let reserve = {};
+ function reservemd(txt) {
+ let id = Math.floor(Math.random()*Math.pow(10, 16)).toString(10).padStart(16, '0');
+ reserve[id] = txt;
+ return `¬r${id}¬r`;
+ }
+ // Escaping + Pre steps
+ text = text
.replaceAll('<', '~lt;')
- .replaceAll('"', '~quot;')
+ .replaceAll('"', '~quot;');
+ if (extended) {
+ text = text.replaceAll(/```([^¬]|¬)*?```/g, function(match){
+ match = match
+ .replaceAll('&', '&')
+ .replaceAll('~lt;', '<')
+ .replaceAll('~quot;', '"');
+ return reservemd(`${match.slice(3,-3)}
`);
+ });
+ }
+ text = text
.replaceAll(/(~lt;https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)>|https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))/g, function(match){
if (match.match(/^~lt;.+?>$/m)) match=match.slice(4,-1);
- return `${match}`
+ return reservemd(`${match}`);
})
.replaceAll('&', '&')
.replaceAll('~lt;', '<')
.replaceAll('~quot;', '"')
- .replaceAll("'", ''')
+ .replaceAll("'", ''');
+ // General
+ text = text
.replaceAll(/\*\*.+?\*\*/g, function(match){return ''+match.slice(2,-2)+''})
.replaceAll(/\*.+?\*/g, function(match){return ''+match.slice(1,-1)+''})
.replaceAll(/\_\_.+?\_\_/g, function(match){return ''+match.slice(2,-2)+''})
.replaceAll(/\_.+?\_/g, function(match){return ''+match.slice(1,-1)+''})
.replaceAll(/\~\~.+?\~\~/g, function(match){return ''+match.slice(2,-2)+''})
.replaceAll(/\|\|.+?\|\|/g, function(match){return ``+match.slice(2,-2)+''})
- .replaceAll(/^\> .+?$/gm, function(match){return '
'+match.slice(2)+'
'})
- .replaceAll(/^### .+?$/gm, function(match){return ''+match.slice(4)+''})
- .replaceAll(/^## .+?$/gm, function(match){return ''+match.slice(3)+''})
- .replaceAll(/^# .+?$/gm, function(match){return ''+match.slice(2)+''})
- .replaceAll(/^-# .+?$/gm, function(match){return ''+match.slice(3)+''})
- .replaceAll(/^(-|\*) .+?$/gm, function(match){return ''+match.slice(2)+''});
+ .replaceAll(/\`.+?\`/g, function(match){return ''+match.slice(1,-1)+'
'})
+ .replaceAll(/^\> .+?$/gm, function(match){return ''+match.slice(2)+'
'});
+ // Discord
+ text = text
+ .replaceAll(/<:.+?:[0-9]+?>/g, function(match){
+ let parts = match.replace('>','').split(':');
+ return `
`;
+ });
+ // Extended
+ if (extended) {
+ text = text
+ .replaceAll(/^### .+?$/gm, function(match){return ''+match.slice(4)+''})
+ .replaceAll(/^## .+?$/gm, function(match){return ''+match.slice(3)+''})
+ .replaceAll(/^# .+?$/gm, function(match){return ''+match.slice(2)+''})
+ .replaceAll(/^-# .+?$/gm, function(match){return ''+match.slice(3)+''})
+ .replaceAll(/^(-|\*) .+?$/gm, function(match){return ''+match.slice(2)+''});
+ }
+ // Reserve
+ text = text.replaceAll(/¬r[0-9]{16}¬r/g, function(match){
+ let id = match.split('¬r')[1];
+ if (reserve[id]) {
+ return reserve[id];
+ } else {
+ return match;
+ }
+ })
+ return text;
}
const channelIcons = {};
function fetchChannelIcon(type) {
@@ -85,9 +125,18 @@ function getUserAvatar(id, hash, size = 64) {
if (hash==='system') return '/media/fshcord.png';
return `https://cdn.discordapp.com/avatars/${id}/${hash}.${hash.startsWith('a_')?'gif':'webp'}?size=${size}`;
}
+
function colorToRGB(color) {
return `#${color.toString(16).padStart(6, '0')}`;
}
+function formateDate(date, format='r') {
+ if (format==='r') {
+ return date;
+ } else {
+ return date;
+ }
+}
+
function loading(text) {
Toastify({
text: 'Loading '+text,
@@ -199,17 +248,33 @@ image -
link -
post_preview
rich -
-video
+video -
*/
+ let c;
switch (embed.type) {
case 'gifv':
return ``;
case 'image':
return `
`;
- /*case 'article':
+ case 'article':
case 'link':
case 'rich':
- return ``*/
+ case 'video':
+ c=[embed.title, embed.description, embed?.author?.name, embed?.provider?.name].filter(e=>!!e).length;
+ return `
+ ${embed.thumbnail&&embed.type!=='video'?`

`:''}
+ ${embed?.provider?.name?`
${embed.provider.name}`:''}
+ ${embed?.author?.name?`
${embed.author.proxy_icon_url?`
`:''}${embed.author.name}`:''}
+ ${embed.title?`
${parseMD(embed.title, false)}`:''}
+ ${embed.description&&embed.type!=='video'?`
${parseMD(embed.description)}`:''}
+ ${embed.fields?`
${embed.fields.map(f=>`
+ ${parseMD(f.name, false)}
+ ${parseMD(f.value)}
+
`).join('')}
`:''}
+ ${embed.video?(embed.video.proxy_url?`
`:`
`):''}
+ ${embed.image&&embed.type!=='video'?`

`:''}
+ ${embed?.footer?.text||embed.timestamp?``:''}
+
`;
default:
report(`Unknown embed type: ${embed.type}`, embed);
return `Unknown embed type: ${embed.type}`;
@@ -219,8 +284,8 @@ function renderMessage(content, author, m) {
return `
- ${author.global_name ?? author.username}${m.edited_timestamp?' · Edited':''}
- ${parseMD(content)}
+ ${author.global_name ?? author.username}${[author.system,m.webhook_id,author.bot].filter(e=>!!e).length?`${author.system?'SYSTEM':(m.webhook_id?'WEBHOOK':(author.bot?'BOT':''))}`:''}${m.edited_timestamp?' · Edited':''}
+ ${parseMD(content)}
${m.attachments.length?m.attachments.map(attach=>{
if (!attach.content_type) attach.content_type='image/'+attach.url.split('?')[0].split('.').slice(-1)[0];
return `<${attach.content_type.startsWith('image/')?'img':attach.content_type.startsWith('audio/')?'audio':attach.content_type.startsWith('video/')?'video':'div'} src="${attach.url}" width="${Math.floor(attach.width/2)}" height="${Math.floor(attach.height/2)}" class="message-attach" controls>${attach.content_type.startsWith('image/')?'':attach.content_type.startsWith('audio/')?'':attach.content_type.startsWith('video/')?'':`${attach.filename} `}`;
@@ -276,7 +341,9 @@ const SystemAuthor = {
id: 0,
avatar: 'system',
global_name: 'System',
- username: 'system'
+ username: 'system',
+ bot: true,
+ system: true
}
function showMessages(list) {
document.getElementById('messages').innerHTML = list.map(m=>{
@@ -549,14 +616,17 @@ if (!localStorage.getItem('token')) {
window.data.settings = settings;
loading('icons')
- await fetchChannelIcon('folder');
- await fetchChannelIcon(0);
- await fetchChannelIcon(1);
- await fetchChannelIcon(2);
- await fetchChannelIcon(3);
- await fetchChannelIcon(5);
- await fetchChannelIcon(15);
- await fetchChannelIcon(16);
+ await Promise.allSettled([
+ fetchChannelIcon('folder'),
+ fetchChannelIcon(0),
+ fetchChannelIcon(1),
+ fetchChannelIcon(2),
+ fetchChannelIcon(3),
+ fetchChannelIcon(5),
+ fetchChannelIcon(13),
+ fetchChannelIcon(15),
+ fetchChannelIcon(16)
+ ]);
loading('servers');
let servers = await proxyFetch('https://discord.com/api/v10/users/@me/guilds');
diff --git a/media/style.css b/media/style.css
index 6e10c6a..5f12fd6 100644
--- a/media/style.css
+++ b/media/style.css
@@ -170,8 +170,6 @@ main {
gap: 10px;
padding: 2px 5px;
border-radius: 1rem;
- word-break: break-word;
- white-space: break-spaces;
transition: 250ms;
}
.message:hover {
@@ -180,6 +178,13 @@ main {
.message .name {
color: var(--text-0);
}
+.message .tag {
+ font-size: 75%;
+ padding: 0px 2px;
+ margin-left: 5px;
+ border-radius: 0.25rem;
+ background-color: var(--blue-1);
+}
.message > img {
height: 40px;
border-radius: 2rem;
@@ -187,6 +192,11 @@ main {
.message > span {
display: flex;
flex-direction: column;
+ width: 100%;
+}
+.message .inner {
+ word-break: break-word;
+ white-space: break-spaces;
}
.message-attach {
max-width: 45%;
@@ -200,20 +210,145 @@ audio.message-attach {
}
div.message-attach {
padding: 15px;
- border: 2px var(--bg-1) solid;
border-radius: 2rem;
background-color: var(--bg-2);
+ transition: background-color 250ms;
+}
+.message:hover div.message-attach {
+ background-color: var(--bg-1);
}
lottie-sticker.message-attach {
width: 160px;
height: 160px;
}
+.message-emoji {
+ width: 18px;
+ height: 18px;
+ object-fit: contain;
+ margin-bottom: -4px;
+}
+.message-rich-embed {
+ display: flex;
+ align-items: flex-start;
+ flex-direction: column;
+ position: relative;
+ width: fit-content;
+ max-width: 80%;
+ margin: 2px;
+ border-radius: 0.5rem;
+ padding: 10px;
+ white-space: normal;
+ background-color: var(--bg-2);
+ transition: background-color 250ms;
+}
+.message-rich-embed::before {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ width: 4px;
+ border-radius: 1rem 0 0 1rem;
+ background-color: var(--embed-color);
+}
+.message:hover .message-rich-embed {
+ background-color: var(--bg-1);
+}
+.message-rich-embed a {
+ text-decoration: none;
+}
+.message-rich-embed a[href]:hover {
+ cursor: pointer;
+ text-decoration: underline;
+}
+.message-rich-embed .thumbnail {
+ position: absolute;
+ top: 10px;
+ right: 12px;
+ width: 50px;
+ height: 50px;
+ margin: 0;
+}
+.message-rich-embed .sub {
+ cursor: auto;
+ font-size: 75%;
+ color: var(--text-2);
+}
+.message-rich-embed .etitle {
+ font-weight: bold;
+}
+.message-rich-embed .etitle:not([href]) {
+ cursor: auto;
+ color: var(--text-1);
+}
+.message-rich-embed .desc {
+ word-break: break-word;
+ white-space: break-spaces;
+}
+.message-rich-embed .fields {
+ display: flex;
+ flex-wrap: wrap;
+ width: 100%;
+}
+.message-rich-embed .fields > div {
+ display: flex;
+ flex: 1 1 33.33%;
+ flex-direction: column;
+}
+.message-rich-embed .footer {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ color: var(--text-2);
+ font-size: 75%;
+}
+.message-rich-embed .footer .text, .message-rich-embed .sub {
+ display: flex;
+ gap: 3px;
+ align-items: center;
+}
+.message-rich-embed .footer img, .message-rich-embed .sub img {
+ width: 15px;
+ height: 15px;
+ border-radius: 2rem;
+}
+.message-rich-embed .footer .dot {
+ width: 4px;
+ height: 4px;
+ border-radius: 2rem;
+ background-color: var(--text-2);
+}
+.message-rich-embed iframe {
+ width: 100%;
+ aspect-ratio: 16 / 9;
+ max-width: 100%;
+ max-height: unset;
+}
+.message code {
+ word-break: break-word;
+ white-space: break-spaces;
+ padding: 2px;
+ border-radius: 0.25rem;
+ background-color: var(--bg-0);
+}
blockquote {
display: unset;
- margin: 0;
- padding-left: 10px;
- border-left: 4px var(--text-2) solid;
+ position: relative;
+ margin: 0px;
+ padding-left: 15px;
+}
+blockquote::before {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ top: -1px;
+ left: 0;
+ width: 4px;
+ height: 22px;
+ border-radius: 1rem;
+ background-color: var(--text-2);
}
.input-bar {