here is a filesize detection script made for reemo
// ==UserScript==
// @name Sockchat EEPROM File Sizes
// @description adds things to eeprom uploads
// @author szy
// @match https://chat.flashii.net/
// @grant none
// ==/UserScript==
(function() {
'use strict';
function xhr(url) { // fucking stolen from osk and then mutilated
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = () => {
if (request.readyState === 4) {
const json = JSON.parse(request.responseText);
if (json) {
resolve(json);
} else {
reject(json);
}
}
};
request.onerror = () => {
console.error(`Request ${url} returned onerror`);
reject();
};
request.send();
});
}
function sizeOf(bytes) { // https://stackoverflow.com/a/28120564
if (bytes == 0) { return "0B"; }
var e = Math.floor(Math.log(bytes) / Math.log(1024));
return (bytes/Math.pow(1024, e)).toFixed(2)+'\u200b'+'\u200bKMGTP'.charAt(e)+'B';
}
window.addEventListener('umi:ui:message_add', function(ev) {
var message = ev.detail.element;
var embeds = message.querySelectorAll('span[title^="//i.flashii.net/"]');
for (var i = 0; i < embeds.length; i++) {
const embed = embeds[i];
try {
let el = document.createElement('span');
el.classList.add('szy_eeprom_data');
el.style.color='#AFF';
el.textContent=' [...]';
embed.appendChild(el);
let href = embed.firstChild.firstChild.href;
let eeprom = href.replace(/i.flashii.net\/([A-Za-z0-9_-]+)/g, "eeprom.flashii.net/uploads/$1.json");
xhr(eeprom).then(resp=>{
var size = +resp['size'];
el.textContent = `[${sizeOf(size)}]`;
el.style.color = '#CDD';
}).catch(err=>{
console.error(err);
el.textContent='[ERR]';
el.style.color='#FAA';
});
} catch (ex) {
console.error(ex);
}
}
});
})();
it also shows the resolution and length if applicable, and for eeprom files, you can hover over the tag to see its original filename
// ==UserScript==
// @name Sockchat Embed File Sizes
// @description adds things to embeds
// @author szy, osk
// @match https://chat.flashii.net/
// @grant none
// ==/UserScript==
(function() {
'use strict';
function xhr(url) {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = () => {
if (request.readyState === 4) {
const json = JSON.parse(request.responseText);
if (json) {
resolve(json);
} else {
reject(json);
}
}
};
request.onerror = () => {
console.error(`Request ${url} returned onerror`);
reject();
};
request.send();
});
}
function sizeOf(bytes) { // https://stackoverflow.com/a/28120564
if (bytes === 0) { return '0B'; }
const e = Math.floor(Math.log(bytes) / Math.log(1024));
return (bytes/Math.pow(1024, e)).toFixed(e === 0 ? 0 : 2)+'\u200b'+'\u200bKMGTP'.charAt(e)+'B';
}
function ParseMS(oms) {
const roms = Math.round(oms);
const ms = roms % 1000;
const s = Math.floor(roms / 1000) % 60;
const m = Math.floor(roms / 60000);
return {
ms: ms.toString().padStart(3, '0'),
s: s.toString().padStart(2, '0'),
m: m.toString()
};
}
window.addEventListener('umi:ui:message_add', function(ev) {
const embedButtons = ev.detail.element.querySelectorAll('a[onclick^="Umi.Parser.SockChatBBcode.Embed"]');
for (const embedButton of embedButtons) {
const embed = embedButton.parentElement;
let link = embed.getAttribute('title');
if (link.startsWith('//')) { link = `https:${ link }`; } // Mii 500s on //domain.name URIs
try {
const el = document.createElement('span');
el.classList.add('eeprom_extended_data');
el.style.color = '#AFF';
el.textContent = ' [...]';
embed.appendChild(el);
xhr(`https://uiharu.flashii.net/metadata?url=${ encodeURIComponent(link) }`).then((resp) => {
if (resp.errorMessage) {
throw resp.errorMessage;
}
if (!resp.media) {
if (resp.content_type) {
throw `Not a media file; detected as ${ resp.content_type.string }`;
}
throw 'Not a media file; content type unknown';
}
let size = resp.media.size || 0;
if (resp.eeprom_file_info) {
size = resp.eeprom_file_info.size;
el.title = resp.eeprom_file_info.name;
}
el.style.color = '#A0F5B8';
if (size >= 128*1024) { el.style.color = '#BAE9C7'; }
if (size >= 512*1024) { el.style.color = '#CDD'; }
if (size >= 1024*1024) { el.style.color = '#CCA1F4'; }
if (size >= 4*1024*1024) { el.style.color = '#DB5FF1'; }
if (size >= 10*1024*1024) { el.style.color = '#EC32A4'; }
let elText = sizeOf(size);
if (resp.is_image && resp.width && resp.height) {
elText += `・${ resp.width }x${ resp.height }`;
}
if (resp.is_video && resp.width && resp.height && resp.media.duration) {
const p = ParseMS(resp.media.duration * 1000);
elText += `・${ resp.width }x${ resp.height }・${ p.m }:${ p.s }<span style="font-size: 70%">.${ p.ms }</span>`;
}
if (resp.is_audio && resp.media.duration) {
const p = ParseMS(resp.media.duration * 1000);
elText += `・${ p.m }:${ p.s }<span style="font-size: 70%">.${ p.ms }</span>`;
}
el.innerHTML = ` [${ elText }]`;
}).catch((err) => {
console.error(err);
el.textContent = '[ERR]';
el.style.color = '#FAA';
el.title = err || 'Network error while requesting metadata';
})
} catch (ex) {
console.error(ex)
}
}
});
})();
double shiftclick to delete a message
// ==UserScript==
// @name Flashii Chat Delete
// @namespace Violentmonkey Scripts
// @match https://chat.flashii.net/
// @grant none
// @version 1.0
// @author osk
// @description 2/25/2021, 11:07:26 PM
// ==/UserScript==
document.addEventListener('click', function(e) {
if (!e.shiftKey) { return; }
if (e.target.closest('.message')) {
if (e.target.closest('.message').classList.contains('deleting')) {
Umi.Server.SendMessage(`/delmsg ${ e.target.closest('.message').id.replace('message-', '') }`);
} else {
e.target.closest('.message').classList.add('deleting');
e.target.closest('.message').setAttribute('style', 'background-color: #400;');
}
}
});
you can also replace the Umi.Server.SendMessage
with Umi.UI.View.SetText
if you dont want it to delete instantly, this will just fill in the command to do so but not send it
this makes the script break a little (since the red mark never goes away) and is redundant with how it requires two clicks anyway but i like it more that way
I'll probably start making some large changes to the chat code sometime soon so I'd like to know what kinda methods scripts hook into so I can keep some kind of compatiblity with them in mind.
The monolithic Umi.Protocol.SockLegacy.Protocol.Instance.SendMessage
is already operating on backwards compat, and Umi.Server.SendMessage
too technically since I changed the casing.
With this I'd also like to fully push through the namespace name change from Umi to Mami so it's in line with the current name of the project (third name change so far!), backwards compatibility shit would obviously still use the Umi namespace because it'd be in vain otherwise.
I have the following APIs already listed:
window.addEventListener(’umi:connect’, handler(event))
window.addEventListener(’umi:ui:message_add’, handler(event: { detail: { element: HTMLDivElement } }))
Umi.Server.SendMessage(text)
Umi.Protocol.SockLegacy.Protocol.Instance.SendMessage(text)
Umi.Parser.SockChatBBcode.EmbedStub()
Umi.UI.View.SetText(text)
Umi.UI.Menus.Add(baseId, title, initiallyHidden)
Umi.UI.Menus.Get(baseId, icon)
There's also querySelectorAll('a[onclick^="Umi.Parser.SockChatBBcode.Embed"]')
which is used in the file size script, but that functionality will be built in pretty much at the same time as the HTML that this tries to pick up on would be removed. Though in the mean time, that's where EmbedStub
comes in.
Let me know if any you use are missing and I'll see if they're within reason. I'll keep the list in this post updated.
// ==UserScript==
// @name Unfix Pictochat sounds
// @version 2024021001
// @grant none
// @match https://chat.flashii.net/
// ==/UserScript==
window.addEventListener('umi:connect', function() {
const picto = unsafeWindow.mami.sound.packs.get('nds');
picto.setEventSound('incoming', 'nds:server');
picto.setEventSound('server', 'nds:incoming');
});
Update I swapped the wrong ones because I don't use the pack updated the script oops thanks osk !!!!
// ==UserScript==
// @name Flashii Chat Delete
// @namespace Violentmonkey Scripts
// @match https://chat.flashii.net/
// @grant none
// @version 1.0
// @author osk
// @author geb
// @description 2/25/2021, 11:07:26 PM
// @description 19:38 21/10/2022 added a timeout to the message deletion dialog -geb
// ==/UserScript==
document.addEventListener('click', function(e) {
function clearTarget() {
e.target.closest('.message').setAttribute('style', 'transition: background-color 250ms ease-out')
e.target.closest('.message').classList.remove('deleting')
}
if (!e.shiftKey) { return; }
if (e.target.closest('.message')) {
if (e.target.closest('.message').classList.contains('deleting')) {
Umi.Server.SendMessage(`/delmsg ${ e.target.closest('.message').id.replace('message-', '') }`);
} else {
e.target.closest('.message').classList.add('deleting');
e.target.closest('.message').setAttribute('style', 'background-color: #400; transition: background-color 250ms ease-out');
setTimeout(() => { clearTarget() }, 5000);
}
}
});
// ==UserScript==
// @name Sockchat Autoembed
// @version 0.15
// @description Autoembed stuff that has an embed button
// @author saikuru0
// @match https://chat.flashii.net/
// @grant none
// ==/UserScript==
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
clickEmbed(node);
});
});
});
observer.observe(document, { childList: true, subtree: true });
function clickEmbed(targetDiv) {
const links = targetDiv.querySelectorAll("div.message__container>div.message__text>span>a.markup__link");
links.forEach(link => {
if (link.textContent == "Embed") {
link.click();
}
});
}