From e18efa6cb924f54cd6044571bf6dd2af7c382803 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 21 Aug 2026 22:00:43 -0400 Subject: [PATCH] Added uwu support --- .../services/suppressor.service.spec.ts | 40 ++++++++++++++++++- .../src/shared/services/suppressor.service.ts | 17 ++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/shared/services/suppressor.service.spec.ts b/packages/backend/src/shared/services/suppressor.service.spec.ts index b9ebfd11..e070e297 100644 --- a/packages/backend/src/shared/services/suppressor.service.spec.ts +++ b/packages/backend/src/shared/services/suppressor.service.spec.ts @@ -118,7 +118,44 @@ describe('SuppressorService', () => { expect(loggerSpy).toHaveBeenCalled(); }); + it('sendSuppressedMessage uwuifies text by replacing r and l with w roughly 5% of the time when there are at least 4 eligible letters', async () => { + vi.spyOn(Math, 'random').mockReturnValue(0.04); + + await suppressorService.sendSuppressedMessage( + 'C123', + 'U1', + 'hello world', + '123', + 1, + suppressorService.muzzlePersistenceService as never, + ); + + expect(suppressorService.translationService.translate).not.toHaveBeenCalled(); + expect(suppressorService.webService.sendMessage).toHaveBeenCalledWith('C123', '<@U1> says "hewwo wowwd"'); + }); + + it('sendSuppressedMessage skips uwu when the text has fewer than 4 r or l letters', async () => { + vi.spyOn(Math, 'random').mockReturnValue(0.04); + + await suppressorService.sendSuppressedMessage( + 'C123', + 'U1', + 'hi there', + '123', + 1, + suppressorService.muzzlePersistenceService as never, + ); + + expect(suppressorService.translationService.translate).toHaveBeenCalledWith('hi there'); + expect(suppressorService.webService.sendMessage).toHaveBeenCalledWith( + 'C123', + expect.stringContaining('<@U1> says'), + ); + }); + it('sendSuppressedMessage uses translation for normal channels', async () => { + vi.spyOn(Math, 'random').mockReturnValue(0.5); + await suppressorService.sendSuppressedMessage( 'C123', 'U1', @@ -128,7 +165,7 @@ describe('SuppressorService', () => { suppressorService.muzzlePersistenceService as never, ); - expect(suppressorService.translationService.translate).toHaveBeenCalled(); + expect(suppressorService.translationService.translate).toHaveBeenCalledWith('hello world'); expect(suppressorService.webService.sendMessage).toHaveBeenCalledWith( 'C123', expect.stringContaining('<@U1> says'), @@ -136,6 +173,7 @@ describe('SuppressorService', () => { }); it('sendSuppressedMessage falls back when translation fails', async () => { + vi.spyOn(Math, 'random').mockReturnValue(0.5); (suppressorService.translationService.translate as Mock).mockRejectedValue(new Error('translate fail')); await suppressorService.sendSuppressedMessage( diff --git a/packages/backend/src/shared/services/suppressor.service.ts b/packages/backend/src/shared/services/suppressor.service.ts index 49e64fb1..3f5d8901 100644 --- a/packages/backend/src/shared/services/suppressor.service.ts +++ b/packages/backend/src/shared/services/suppressor.service.ts @@ -203,6 +203,14 @@ export class SuppressorService { } } + public uwuifyText(text: string): string { + return text.replace(/[rRlL]/g, 'w'); + } + + public shouldUwuifyText(text: string): boolean { + return (text.match(/[rRlL]/g) ?? []).length >= 4; + } + public async sendSuppressedMessage( channel: string, userId: string, @@ -218,7 +226,6 @@ export class SuppressorService { } const words: string[] | undefined = text.split(' '); - const shouldMuzzle = words.length <= 250; if (shouldMuzzle) { @@ -246,8 +253,12 @@ export class SuppressorService { return null; }); } else { - await this.translationService - .translate(textWithFallbackReplacments) + const shouldUwuify = Math.random() < 0.05 && this.shouldUwuifyText(textWithFallbackReplacments); + await ( + shouldUwuify + ? Promise.resolve(this.uwuifyText(textWithFallbackReplacments)) + : this.translationService.translate(textWithFallbackReplacments) + ) .then(async (message) => { await this.logTranslateSuppression(text, dbId, persistenceService); await this.webService