Files
cinny/src/app/plugins/soundboard/utils.ts
T

104 lines
3.9 KiB
TypeScript
Raw Normal View History

import { MatrixClient, MatrixEvent, Room } from 'matrix-js-sdk';
import { SoundboardPack } from './SoundboardPack';
import {
LegacySoundboardContent,
SoundboardClips,
SoundboardContent,
SoundboardRoomsContent,
} from './types';
import { StateEvent } from '../../../types/matrix/room';
import { AccountDataEvent } from '../../../types/matrix/accountData';
import { getAccountData, getStateEvent, getStateEvents } from '../../utils/room';
/** Normalize a display name into a pack shortcode key (parallels emoji shortcodes). */
export function slugifyClipName(name: string): string {
const s = name
.trim()
.toLowerCase()
.replace(/\s+/g, '_')
.replace(/[^a-z0-9_-]/g, '');
return s || 'clip';
}
/** Pick a shortcode not already present in `taken`, suffixing on collision. */
export function uniqueShortcode(base: string, taken: Set<string>): string {
const code = slugifyClipName(base);
if (!taken.has(code)) return code;
let i = 2;
while (taken.has(`${code}-${i}`)) i += 1;
return `${code}-${i}`;
}
export function makeSoundboardPacks(packEvents: MatrixEvent[]): SoundboardPack[] {
return packEvents.reduce<SoundboardPack[]>((packs, packEvent) => {
const packId = packEvent.getId();
if (!packId) return packs;
packs.push(SoundboardPack.fromMatrixEvent(packId, packEvent));
return packs;
}, []);
}
export function getRoomSoundboardPack(room: Room, stateKey: string): SoundboardPack | undefined {
const packEvent = getStateEvent(room, StateEvent.LotusSoundboardRoom, stateKey);
if (!packEvent) return undefined;
const packId = packEvent.getId();
if (!packId) return undefined;
return SoundboardPack.fromMatrixEvent(packId, packEvent);
}
export function getRoomSoundboardPacks(room: Room): SoundboardPack[] {
return makeSoundboardPacks(getStateEvents(room, StateEvent.LotusSoundboardRoom));
}
export function getGlobalSoundboardPacks(mx: MatrixClient): SoundboardPack[] {
const content = getAccountData(mx, AccountDataEvent.LotusSoundboardRooms)?.getContent() as
| SoundboardRoomsContent
| undefined;
const roomIdToPackInfo = content?.rooms;
if (typeof roomIdToPackInfo !== 'object' || !roomIdToPackInfo) return [];
return Object.keys(roomIdToPackInfo).flatMap((roomId) => {
if (typeof roomIdToPackInfo[roomId] !== 'object') return [];
const room = mx.getRoom(roomId);
if (!room) return [];
const stateKeys = roomIdToPackInfo[roomId];
const globalEvents = getStateEvents(room, StateEvent.LotusSoundboardRoom).filter((mE) => {
const stateKey = mE.getStateKey();
return typeof stateKey === 'string' ? !!stateKeys[stateKey] : false;
});
return makeSoundboardPacks(globalEvents);
});
}
/**
* Convert a personal soundboard account-data content to the v2 pack shape,
* migrating the v1 flat-list form (`{clips: [{id,name,url}]}`) on the fly.
*/
export function migrateUserSoundboardContent(raw: unknown): SoundboardContent {
if (typeof raw !== 'object' || raw === null) return {};
const legacy = raw as LegacySoundboardContent;
if (!Array.isArray(legacy.clips)) return raw as SoundboardContent; // already v2 (or empty)
const clips: SoundboardClips = {};
const taken = new Set<string>();
legacy.clips.forEach((c) => {
if (!c || typeof c.url !== 'string') return;
const shortcode = uniqueShortcode(c.name || 'clip', taken);
taken.add(shortcode);
clips[shortcode] = {
url: c.url,
body: c.name,
info: { mimetype: c.mimetype, size: c.size },
};
});
return { pack: { display_name: 'My Soundboard' }, clips };
}
export function getUserSoundboardPack(mx: MatrixClient): SoundboardPack | undefined {
const packEvent = getAccountData(mx, AccountDataEvent.LotusSoundboard);
const userId = mx.getUserId();
if (!packEvent || !userId) return undefined;
const content = migrateUserSoundboardContent(packEvent.getContent());
return new SoundboardPack(userId, content, undefined);
}