From 481e42a44269e1f3bcc27186eee0fdb33adc5404 Mon Sep 17 00:00:00 2001 From: AlejandroAkbal <37181533+AlejandroAkbal@users.noreply.github.com> Date: Mon, 16 Mar 2026 01:43:06 -0700 Subject: [PATCH 1/2] add kemono booru type compatibility --- src/booru/booru.service.spec.ts | 28 +++++++++++++++++++++++++++- src/booru/booru.service.ts | 17 +++++++++++++++-- src/booru/dto/request-booru.dto.ts | 8 ++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/booru/booru.service.spec.ts b/src/booru/booru.service.spec.ts index a12f69c..5e4f1d1 100644 --- a/src/booru/booru.service.spec.ts +++ b/src/booru/booru.service.spec.ts @@ -3,7 +3,7 @@ import { ConfigService } from '@nestjs/config' import { BooruTypesStringEnum } from '@alejandroakbal/universal-booru-wrapper' import { BooruService } from './booru.service' import { booruQueriesDTO } from './dto/booru-queries.dto' -import { BooruEndpointParamsDTO } from './dto/request-booru.dto' +import { BooruEndpointParamsDTO, SupportedBooruType } from './dto/request-booru.dto' import { BooruAuthManagerService } from './services/booru-auth-manager.service' describe('BooruService', () => { @@ -123,4 +123,30 @@ describe('BooruService', () => { }) + + describe('Booru type resolution', () => { + it('should resolve kemono when supported and fail clearly otherwise', () => { + const maybeKemonoClass = (require('@alejandroakbal/universal-booru-wrapper') as any).Kemono + + const params: BooruEndpointParamsDTO = { + booruType: 'kemono' as SupportedBooruType + } + + const queries = { + baseEndpoint: 'kemono.cr' + } as booruQueriesDTO + + if (maybeKemonoClass) { + const api = service.buildApiClass(params, queries) + + expect(api).toBeInstanceOf(maybeKemonoClass) + + return + } + + expect(() => service.buildApiClass(params, queries)).toThrow( + 'Kemono booru type requires @alejandroakbal/universal-booru-wrapper version that exports Kemono' + ) + }) + }) }) diff --git a/src/booru/booru.service.ts b/src/booru/booru.service.ts index 5aa1f73..c32e422 100644 --- a/src/booru/booru.service.ts +++ b/src/booru/booru.service.ts @@ -16,8 +16,9 @@ import { Rule34PahealNet, Rule34Xxx } from '@alejandroakbal/universal-booru-wrapper' +import * as UBW from '@alejandroakbal/universal-booru-wrapper' import { booruQueriesDTO } from './dto/booru-queries.dto' -import { BooruEndpointParamsDTO } from './dto/request-booru.dto' +import { BooruEndpointParamsDTO, SupportedBooruType } from './dto/request-booru.dto' import { BooruAuthManagerService } from './services/booru-auth-manager.service' @Injectable() @@ -112,7 +113,7 @@ export class BooruService { return {} } - private getApiClassByType(booruType: BooruTypesStringEnum) { + private getApiClassByType(booruType: SupportedBooruType) { switch (booruType) { case BooruTypesStringEnum.DANBOORU: return Danbooru @@ -140,6 +141,18 @@ export class BooruService { case BooruTypesStringEnum.REALBOORU_COM: return RealBooruCom + + case 'kemono': { + const maybeKemonoClass = (UBW as any).Kemono + + if (!maybeKemonoClass) { + throw new Error( + 'Kemono booru type requires @alejandroakbal/universal-booru-wrapper version that exports Kemono' + ) + } + + return maybeKemonoClass + } } } } diff --git a/src/booru/dto/request-booru.dto.ts b/src/booru/dto/request-booru.dto.ts index a8dfa99..1dc89d6 100644 --- a/src/booru/dto/request-booru.dto.ts +++ b/src/booru/dto/request-booru.dto.ts @@ -1,12 +1,16 @@ import { BooruTypesStringEnum } from '@alejandroakbal/universal-booru-wrapper' import { IsDefined, IsIn, IsNotEmpty, IsString } from 'class-validator' -const BooruTypesToArray = Object.values(BooruTypesStringEnum) +const AdditionalBooruTypes = ['kemono'] as const + +export type SupportedBooruType = BooruTypesStringEnum | (typeof AdditionalBooruTypes)[number] + +const BooruTypesToArray = [...Object.values(BooruTypesStringEnum), ...AdditionalBooruTypes] export class BooruEndpointParamsDTO { @IsDefined() @IsNotEmpty() @IsString() @IsIn(BooruTypesToArray) - readonly booruType: BooruTypesStringEnum + readonly booruType: SupportedBooruType } From f9ad09b963e1e2b37e7aae9a80aab3e123ea3982 Mon Sep 17 00:00:00 2001 From: AlejandroAkbal <37181533+AlejandroAkbal@users.noreply.github.com> Date: Mon, 16 Mar 2026 01:53:00 -0700 Subject: [PATCH 2/2] clarify kemono compatibility errors --- src/booru/booru.service.spec.ts | 33 ++++++++++++++++++++++++--------- src/booru/booru.service.ts | 7 +++++-- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/booru/booru.service.spec.ts b/src/booru/booru.service.spec.ts index 5e4f1d1..e4a6267 100644 --- a/src/booru/booru.service.spec.ts +++ b/src/booru/booru.service.spec.ts @@ -1,6 +1,7 @@ import { Test, TestingModule } from '@nestjs/testing' import { ConfigService } from '@nestjs/config' import { BooruTypesStringEnum } from '@alejandroakbal/universal-booru-wrapper' +import * as UBW from '@alejandroakbal/universal-booru-wrapper' import { BooruService } from './booru.service' import { booruQueriesDTO } from './dto/booru-queries.dto' import { BooruEndpointParamsDTO, SupportedBooruType } from './dto/request-booru.dto' @@ -125,23 +126,37 @@ describe('BooruService', () => { }) describe('Booru type resolution', () => { - it('should resolve kemono when supported and fail clearly otherwise', () => { - const maybeKemonoClass = (require('@alejandroakbal/universal-booru-wrapper') as any).Kemono + const queries = { + baseEndpoint: 'kemono.cr' + } as booruQueriesDTO + + afterEach(() => { + if ((UBW as any).Kemono !== originalKemonoClass) { + ;(UBW as any).Kemono = originalKemonoClass + } + }) + + const originalKemonoClass = (UBW as any).Kemono + + it('should resolve kemono when the wrapper exports it', () => { + if (!originalKemonoClass) { + return + } const params: BooruEndpointParamsDTO = { booruType: 'kemono' as SupportedBooruType } - const queries = { - baseEndpoint: 'kemono.cr' - } as booruQueriesDTO + const api = service.buildApiClass(params, queries) - if (maybeKemonoClass) { - const api = service.buildApiClass(params, queries) + expect(api).toBeInstanceOf(originalKemonoClass) + }) - expect(api).toBeInstanceOf(maybeKemonoClass) + it('should fail clearly when the wrapper does not export kemono', () => { + ;(UBW as any).Kemono = undefined - return + const params: BooruEndpointParamsDTO = { + booruType: 'kemono' as SupportedBooruType } expect(() => service.buildApiClass(params, queries)).toThrow( diff --git a/src/booru/booru.service.ts b/src/booru/booru.service.ts index c32e422..438ddd9 100644 --- a/src/booru/booru.service.ts +++ b/src/booru/booru.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common' +import { BadRequestException, Injectable, ServiceUnavailableException } from '@nestjs/common' import { ConfigService } from '@nestjs/config' import { BooruTypes, @@ -146,13 +146,16 @@ export class BooruService { const maybeKemonoClass = (UBW as any).Kemono if (!maybeKemonoClass) { - throw new Error( + throw new ServiceUnavailableException( 'Kemono booru type requires @alejandroakbal/universal-booru-wrapper version that exports Kemono' ) } return maybeKemonoClass } + + default: + throw new BadRequestException(`Unsupported booru type: ${booruType}`) } } }