274 lines
10 KiB
JavaScript
274 lines
10 KiB
JavaScript
const tinyWave = 'data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAESsAACJWAAACABAAZGF0YQAAAAA=';
|
|
const originalMessage = 'Plugin API original message';
|
|
const editedMessage = 'Plugin API edited message';
|
|
const deletedMessage = 'Plugin API deleted message';
|
|
const embedMessage = 'toju:embed:e2e.coverage:{"title":"Plugin API custom embed","body":"Rendered by plugin API"}';
|
|
const soundboardPlayedMessage = 'E2E soundboard played Airhorn to voice channel';
|
|
|
|
export async function activate(context) {
|
|
const api = context.api;
|
|
const currentUser = api.profile.getCurrent();
|
|
const shouldMutateChat = !currentUser?.displayName?.includes('Bob');
|
|
const pluginUserId = api.server.registerPluginUser({
|
|
displayName: 'E2E Plugin Bot',
|
|
id: 'e2e-plugin-bot'
|
|
});
|
|
|
|
context.subscriptions.push(api.ui.registerSettingsPage('coverage', {
|
|
label: 'E2E Coverage',
|
|
render: () => 'E2E settings contribution'
|
|
}));
|
|
context.subscriptions.push(api.ui.registerAppPage('coverage', {
|
|
label: 'E2E Page',
|
|
path: '/plugins/e2e/coverage',
|
|
render: () => 'E2E page contribution'
|
|
}));
|
|
context.subscriptions.push(api.ui.registerSidePanel('coverage', {
|
|
label: 'E2E Soundboard',
|
|
render: () => 'E2E soundboard ready'
|
|
}));
|
|
context.subscriptions.push(api.ui.registerChannelSection('coverage', {
|
|
label: 'E2E Soundboard',
|
|
type: 'custom'
|
|
}));
|
|
context.subscriptions.push(api.ui.registerComposerAction('coverage', {
|
|
icon: 'SFX',
|
|
label: 'E2E Soundboard',
|
|
run: () => openSoundboardModal(api, pluginUserId)
|
|
}));
|
|
context.subscriptions.push(api.ui.registerProfileAction('coverage', {
|
|
label: 'E2E Profile',
|
|
run: () => api.logger.info('profile action ran')
|
|
}));
|
|
context.subscriptions.push(api.ui.registerToolbarAction('coverage', {
|
|
label: 'E2E Toolbar',
|
|
run: () => api.logger.info('toolbar action ran')
|
|
}));
|
|
context.subscriptions.push(api.ui.registerEmbedRenderer('coverage', {
|
|
embedType: 'e2e.coverage',
|
|
render: (payload) => `E2E custom embed: ${payload?.title ?? 'missing title'}`
|
|
}));
|
|
|
|
const injectedBadge = document.createElement('div');
|
|
|
|
injectedBadge.dataset.testid = 'e2e-plugin-owned-dom';
|
|
injectedBadge.textContent = 'E2E plugin-owned DOM injected into chat';
|
|
injectedBadge.style.position = 'absolute';
|
|
injectedBadge.style.left = '1rem';
|
|
injectedBadge.style.bottom = '5.5rem';
|
|
injectedBadge.style.zIndex = '20';
|
|
injectedBadge.style.border = '1px solid hsl(var(--border))';
|
|
injectedBadge.style.borderRadius = '0.5rem';
|
|
injectedBadge.style.padding = '0.35rem 0.5rem';
|
|
injectedBadge.style.background = 'hsl(var(--card))';
|
|
injectedBadge.style.color = 'hsl(var(--foreground))';
|
|
injectedBadge.style.fontSize = '0.75rem';
|
|
context.subscriptions.push(api.ui.mountElement('chat-owned-badge', {
|
|
element: injectedBadge,
|
|
target: 'app-chat-messages'
|
|
}));
|
|
|
|
context.subscriptions.push(api.events.subscribeServer({ eventName: 'e2e:server', handler: () => {} }));
|
|
context.subscriptions.push(api.events.subscribeP2p({ eventName: 'e2e:p2p', handler: () => {} }));
|
|
|
|
api.storage.set('coverage', { ok: true });
|
|
api.storage.get('coverage');
|
|
await api.serverData.write('coverage', { ok: true });
|
|
await api.serverData.read('coverage');
|
|
|
|
api.profile.update({
|
|
description: 'Updated by E2E plugin',
|
|
displayName: `${currentUser?.displayName || 'E2E Plugin User'} Plugin Renamed`
|
|
});
|
|
api.profile.updateAvatar({
|
|
avatarHash: 'e2e-plugin-avatar',
|
|
avatarMime: 'image/svg+xml',
|
|
avatarUrl: '/plugins/e2e-all-api/icon.svg'
|
|
});
|
|
|
|
api.users.getCurrent();
|
|
api.users.list();
|
|
api.users.readMembers();
|
|
api.users.setRole(pluginUserId, 'member');
|
|
api.users.kick(pluginUserId);
|
|
api.users.ban(pluginUserId, 'E2E coverage');
|
|
|
|
api.roles.list();
|
|
api.roles.setAssignments([]);
|
|
|
|
api.channels.list();
|
|
api.channels.addAudioChannel({ id: 'e2e-audio', name: 'E2E Audio', position: 90 });
|
|
api.channels.addVideoChannel({ id: 'e2e-video', name: 'E2E Video', position: 91 });
|
|
api.channels.select('general');
|
|
api.channels.rename('e2e-audio', 'E2E Audio Renamed');
|
|
|
|
api.server.getCurrent();
|
|
api.server.updatePermissions({ allowVoice: true });
|
|
api.server.updateSettings({
|
|
name: api.server.getCurrent()?.name,
|
|
topic: 'Updated by E2E plugin'
|
|
});
|
|
|
|
api.messages.readCurrent();
|
|
if (shouldMutateChat) {
|
|
const sentMessage = api.messages.send(originalMessage);
|
|
|
|
api.messages.edit(sentMessage.id, editedMessage);
|
|
|
|
const removableMessage = api.messages.send(deletedMessage);
|
|
|
|
api.messages.delete(removableMessage.id);
|
|
api.messages.send(embedMessage);
|
|
}
|
|
|
|
api.messages.sendAsPluginUser({
|
|
content: 'Plugin bot message from all-api fixture',
|
|
pluginUserId
|
|
});
|
|
api.messages.moderateDelete('missing-message-id');
|
|
api.messages.sync(api.messages.readCurrent());
|
|
|
|
api.p2p.connectedPeers();
|
|
api.p2p.broadcastData('e2e:p2p', { ok: true });
|
|
api.p2p.sendData('missing-peer', 'e2e:p2p', { ok: true });
|
|
api.events.publishServer('e2e:server', { ok: true });
|
|
api.events.publishP2p('e2e:p2p', { ok: true });
|
|
|
|
api.media.setOutputVolume(0.8);
|
|
api.media.setInputVolume(0.8);
|
|
await api.media.playAudioClip({ url: tinyWave, volume: 0 }).catch((error) => api.logger.warn('audio clip rejected', String(error)));
|
|
await api.media.addCustomVideoStream({ label: 'e2e-video', stream: new MediaStream() });
|
|
|
|
const audioContext = new AudioContext();
|
|
const destination = audioContext.createMediaStreamDestination();
|
|
|
|
await api.media.addCustomAudioStream({ label: 'e2e-audio', stream: destination.stream }).catch((error) => api.logger.warn('audio stream rejected', String(error)));
|
|
await audioContext.close();
|
|
|
|
api.storage.remove('coverage');
|
|
await api.serverData.remove('coverage');
|
|
api.logger.info('all-api plugin completed');
|
|
}
|
|
|
|
export function ready(context) {
|
|
context.api.logger.info('all-api plugin ready');
|
|
}
|
|
|
|
export function deactivate(context) {
|
|
context.api.logger.info('all-api plugin deactivated');
|
|
}
|
|
|
|
function openSoundboardModal(api, pluginUserId) {
|
|
document.querySelector('[data-testid="e2e-soundboard-modal"]')?.remove();
|
|
|
|
const overlay = document.createElement('div');
|
|
|
|
overlay.dataset.testid = 'e2e-soundboard-modal';
|
|
overlay.setAttribute('role', 'dialog');
|
|
overlay.setAttribute('aria-modal', 'true');
|
|
overlay.setAttribute('aria-label', 'E2E Soundboard');
|
|
overlay.style.position = 'fixed';
|
|
overlay.style.inset = '0';
|
|
overlay.style.zIndex = '9999';
|
|
overlay.style.display = 'grid';
|
|
overlay.style.placeItems = 'center';
|
|
overlay.style.background = 'rgb(0 0 0 / 0.45)';
|
|
|
|
const panel = document.createElement('section');
|
|
|
|
panel.style.width = 'min(24rem, calc(100vw - 2rem))';
|
|
panel.style.border = '1px solid hsl(var(--border))';
|
|
panel.style.borderRadius = '0.5rem';
|
|
panel.style.padding = '1rem';
|
|
panel.style.color = 'hsl(var(--foreground))';
|
|
panel.style.background = 'hsl(var(--card))';
|
|
panel.style.boxShadow = '0 1.25rem 3rem rgb(0 0 0 / 0.25)';
|
|
|
|
const title = document.createElement('h2');
|
|
|
|
title.textContent = 'E2E Soundboard';
|
|
title.style.margin = '0 0 0.75rem';
|
|
title.style.fontSize = '1rem';
|
|
|
|
const status = document.createElement('p');
|
|
|
|
status.dataset.testid = 'e2e-soundboard-status';
|
|
status.textContent = 'Ready to play to voice channel';
|
|
status.style.margin = '0 0 1rem';
|
|
status.style.color = 'hsl(var(--muted-foreground))';
|
|
status.style.fontSize = '0.875rem';
|
|
|
|
const actions = document.createElement('div');
|
|
|
|
actions.style.display = 'flex';
|
|
actions.style.gap = '0.5rem';
|
|
actions.style.justifyContent = 'flex-end';
|
|
|
|
const closeButton = document.createElement('button');
|
|
|
|
closeButton.type = 'button';
|
|
closeButton.textContent = 'Close';
|
|
closeButton.style.border = '1px solid hsl(var(--border))';
|
|
closeButton.style.borderRadius = '0.375rem';
|
|
closeButton.style.padding = '0.5rem 0.75rem';
|
|
closeButton.style.background = 'transparent';
|
|
closeButton.style.color = 'hsl(var(--foreground))';
|
|
closeButton.addEventListener('click', () => overlay.remove());
|
|
|
|
const playButton = document.createElement('button');
|
|
|
|
playButton.type = 'button';
|
|
playButton.textContent = 'Play airhorn to voice';
|
|
playButton.style.border = '0';
|
|
playButton.style.borderRadius = '0.375rem';
|
|
playButton.style.padding = '0.5rem 0.75rem';
|
|
playButton.style.background = 'hsl(var(--primary))';
|
|
playButton.style.color = 'hsl(var(--primary-foreground))';
|
|
playButton.addEventListener('click', async () => {
|
|
playButton.disabled = true;
|
|
status.textContent = 'Playing Airhorn to voice channel';
|
|
|
|
try {
|
|
await playSoundboardClipToVoice(api);
|
|
api.p2p.broadcastData('e2e:p2p', { sound: 'airhorn', source: 'soundboard' });
|
|
api.events.publishP2p('e2e:p2p', { sound: 'airhorn', source: 'soundboard' });
|
|
api.messages.sendAsPluginUser({ content: soundboardPlayedMessage, pluginUserId });
|
|
api.logger.info('soundboard played to voice channel');
|
|
status.textContent = soundboardPlayedMessage;
|
|
} catch (error) {
|
|
status.textContent = error instanceof Error ? error.message : 'Soundboard playback failed';
|
|
api.logger.warn('soundboard playback failed', String(error));
|
|
} finally {
|
|
playButton.disabled = false;
|
|
}
|
|
});
|
|
|
|
actions.append(closeButton, playButton);
|
|
panel.append(title, status, actions);
|
|
overlay.append(panel);
|
|
api.ui.mountElement('soundboard-modal', {
|
|
element: overlay,
|
|
target: 'body'
|
|
});
|
|
}
|
|
|
|
async function playSoundboardClipToVoice(api) {
|
|
const audioContext = new AudioContext();
|
|
const oscillator = audioContext.createOscillator();
|
|
const gain = audioContext.createGain();
|
|
const destination = audioContext.createMediaStreamDestination();
|
|
|
|
oscillator.type = 'square';
|
|
oscillator.frequency.value = 330;
|
|
gain.gain.value = 0.08;
|
|
oscillator.connect(gain);
|
|
gain.connect(destination);
|
|
oscillator.start();
|
|
|
|
await api.media.addCustomAudioStream({ label: 'e2e-soundboard-airhorn', stream: destination.stream });
|
|
await api.media.playAudioClip({ url: tinyWave, volume: 0 }).catch((error) => api.logger.warn('soundboard preview rejected', String(error)));
|
|
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
oscillator.stop();
|
|
await audioContext.close();
|
|
}
|