Skip to content

Create image command #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/commands/gif/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ describe('Waifu Command', () => {
const embed = generateGifEmbed(data, reaction);

expect(embed.title).not.toBeUndefined();
expect(embed.title).toBe('Gif Command | Test reaction');
expect(embed.title).toBe('Random Gif | Test reaction');
});
});
4 changes: 2 additions & 2 deletions src/commands/gif/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { AppCommand, AppCommandOptions } from '../commands';
export const generateGifEmbed = (data: OtakuAPISchema, reaction: string): APIEmbed => {
const color = parseInt('#ff0055'.replace('#', '0x'));
const embed: APIEmbed = {
title: `Gif Command | ${capitalize(reaction)}`,
title: `Random Gif | ${capitalize(reaction)}`,
color,
image: {
url: data.url,
Expand All @@ -18,7 +18,7 @@ export const generateGifEmbed = (data: OtakuAPISchema, reaction: string): APIEmb
};

export default {
commandType: 'Waifu',
commandType: 'Anime',
data: new SlashCommandBuilder().setName('gif').setDescription('Shows a random anime gif'),
async execute({ interaction }: AppCommandOptions) {
try {
Expand Down
132 changes: 132 additions & 0 deletions src/commands/image/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { generateImageEmbed } from '.';
import { NekosImageSchema } from '../../schemas/nekos';

const props: NekosImageSchema = {
id: 'an id',
url: 'a url',
artist: null,
source: {
name: null,
url: null,
},
nsfw: false,
original: false,
categories: [],
characters: [],
createdAt: 'a date',
meta: {
eTag: 'an etag',
size: 1234,
mimetype: 'a mimetype',
color: 'a color',
expires: 'a date',
dimens: {
width: 1234,
height: 4321,
aspectRatio: 'an aspect ratio',
orientation: 'an orientation',
},
},
};

describe('Image Command', () => {
it('generates an embed correctly', () => {
const embed = generateImageEmbed(props);

expect(embed).not.toBeUndefined();
});
it('displays the correct fields in the embed', () => {
const embed = generateImageEmbed(props);

expect(embed.color).not.toBeUndefined();
expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields.length).toBe(2);
});
it('does not display the description if source name is null', () => {
const embed = generateImageEmbed(props);

expect(embed.description).toBeUndefined();
});
it('does not display the description if source url is null', () => {
const embed = generateImageEmbed(props);

expect(embed.description).toBeUndefined();
});
it('displays the description if both source name and source url is defined', () => {
const embed = generateImageEmbed({ ...props, source: { name: 'Test name', url: 'Test url' } });

expect(embed.description).not.toBeUndefined();
});
it('shows the correct color in the embed', () => {
const embed = generateImageEmbed({ ...props, meta: { ...props.meta, color: '#800000' } });

expect(embed.color).not.toBeUndefined();
expect(embed.color).toBe(8388608);
});
it('shows the correct artist in the embed if there is no artist', () => {
const embed = generateImageEmbed(props);

expect(embed.fields && embed.fields[0].name).toBe('Artist');
expect(embed.fields && embed.fields[0].value).toBe('-');
});
it('shows the correct artist in the embed if there is an artist', () => {
const artist = {
id: '1',
name: 'Test artist',
url: 'a url',
images: 1234,
};
const embed = generateImageEmbed({ ...props, artist });

expect(embed.fields && embed.fields[0].name).toBe('Artist');
expect(embed.fields && embed.fields[0].value).toBe('Test artist');
});
it('shows the correct categories in the embed if there are no categories', () => {
const embed = generateImageEmbed({ ...props, categories: [] });

expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields[1].name).toBe('Tags');
expect(embed.fields && embed.fields[1].value).toBe('-');
});
it('shows the correct category in the embed if there is only one category', () => {
const categories = [
{
id: '1',
name: 'Girl',
description: 'a description',
nsfw: false,
createdAt: 'some date',
},
];
const embed = generateImageEmbed({ ...props, categories });

expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields[1].name).toBe('Tags');
expect(embed.fields && embed.fields[1].value.includes(',')).toBe(false);
expect(embed.fields && embed.fields[1].value).toBe('Girl');
});
it('shows the correct categories in the embed if there are a couple of categories', () => {
const categories = [
{
id: '1',
name: 'Girl',
description: 'a description',
nsfw: false,
createdAt: 'some date',
},
{
id: '2',
name: 'Nekomimi',
description: 'a description',
nsfw: false,
createdAt: 'some date',
},
];
const embed = generateImageEmbed({ ...props, categories });

expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields[1].name).toBe('Tags');
expect(embed.fields && embed.fields[1].value.includes(',')).toBe(true);
expect(embed.fields && embed.fields[1].value).toBe('Girl, Nekomimi');
});
});
59 changes: 59 additions & 0 deletions src/commands/image/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { APIEmbed, hyperlink, SlashCommandBuilder } from 'discord.js';
import { isEmpty, reduce } from 'lodash';
import { NekosImageSchema } from '../../schemas/nekos';
import { getNekosImage } from '../../services/adapters';
import { sendErrorLog } from '../../utils/helpers';
import { AppCommand, AppCommandOptions } from '../commands';

export const generateImageEmbed = (data: NekosImageSchema): APIEmbed => {
const color = parseInt(data.meta.color.replace('#', '0x'));
const tags = reduce(
data.categories,
(accumulator, value) => {
return `${accumulator}${isEmpty(accumulator) ? '' : ', '}${value.name}`;
},
''
);
const embed: APIEmbed = {
title: 'Random Image',
description:
data.source.url && data.source.name
? `${hyperlink('Source URL', data.source.url)} | ${hyperlink(
'Source Name',
data.source.name
)}`
: undefined,
color,
image: {
url: data.url,
},
fields: [
{
name: 'Artist',
value: data.artist ? data.artist.name : '-',
inline: true,
},
{
name: 'Tags',
value: isEmpty(tags) ? '-' : tags,
inline: true,
},
],
};
return embed;
};

export default {
commandType: 'Anime',
data: new SlashCommandBuilder().setName('image').setDescription('Shows a random anime image'),
async execute({ interaction }: AppCommandOptions) {
try {
await interaction.deferReply();
const data = await getNekosImage();
const embed = generateImageEmbed(data);
await interaction.editReply({ embeds: [embed] });
} catch (error) {
sendErrorLog({ error, interaction });
}
},
} as AppCommand;
34 changes: 10 additions & 24 deletions src/commands/waifu/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Waifu Command', () => {
expect(embed.description).not.toBeUndefined();
expect(embed.color).not.toBeUndefined();
expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields.length).toBe(2);
expect(embed.fields && embed.fields.length).toBe(1);
});
it('shows the correct color in the embed', () => {
const embed = generateWaifuEmbed({ ...props, dominant_color: '#800000' });
Expand All @@ -50,10 +50,10 @@ describe('Waifu Command', () => {
const embed = generateWaifuEmbed({ ...props, tags: [] });

expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields[1].name).toBe('Tags');
expect(embed.fields && embed.fields[1].value).toBe('');
expect(embed.fields && embed.fields[0].name).toBe('Tags');
expect(embed.fields && embed.fields[0].value).toBe('-');
});
it('shows the correct tags in the embed if there is only one tag', () => {
it('shows the correct tag in the embed if there is only one tag', () => {
const tags = [
{
tag_id: 1,
Expand All @@ -65,9 +65,9 @@ describe('Waifu Command', () => {
const embed = generateWaifuEmbed({ ...props, tags });

expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields[1].name).toBe('Tags');
expect(embed.fields && embed.fields[1].value.includes(',')).toBe(false);
expect(embed.fields && embed.fields[1].value).toBe('waifu');
expect(embed.fields && embed.fields[0].name).toBe('Tags');
expect(embed.fields && embed.fields[0].value.includes(',')).toBe(false);
expect(embed.fields && embed.fields[0].value).toBe('waifu');
});
it('shows the correct tags in the embed if there are a couple of tags', () => {
const tags = [
Expand All @@ -87,22 +87,8 @@ describe('Waifu Command', () => {
const embed = generateWaifuEmbed({ ...props, tags });

expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields[1].name).toBe('Tags');
expect(embed.fields && embed.fields[1].value.includes(',')).toBe(true);
expect(embed.fields && embed.fields[1].value).toBe('waifu, uniform');
});
it('shows the correct orientation if width is larger than height', () => {
const embed = generateWaifuEmbed({ ...props, width: 1200, height: 1000 });

expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields[0].name).toBe('Orientation');
expect(embed.fields && embed.fields[0].value).toBe('Landscape');
});
it('shows the correct orientation if height is larger than width', () => {
const embed = generateWaifuEmbed({ ...props, width: 1000, height: 1200 });

expect(embed.fields).not.toBeUndefined();
expect(embed.fields && embed.fields[0].name).toBe('Orientation');
expect(embed.fields && embed.fields[0].value).toBe('Portrait');
expect(embed.fields && embed.fields[0].name).toBe('Tags');
expect(embed.fields && embed.fields[0].value.includes(',')).toBe(true);
expect(embed.fields && embed.fields[0].value).toBe('waifu, uniform');
});
});
11 changes: 3 additions & 8 deletions src/commands/waifu/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,17 @@ export const generateWaifuEmbed = (data: WaifuSchema): APIEmbed => {
},
''
);
const orientation: 'Portrait' | 'Landscape' = data.width > data.height ? 'Landscape' : 'Portrait';
const embed: APIEmbed = {
title: 'Random Waifu',
color,
description: `${hyperlink('Source', data.source)} | ${hyperlink('Preview', data.preview_url)}`,
image: {
url: data.url,
},
fields: [
{
name: 'Orientation',
value: orientation,
inline: true,
},
{
name: 'Tags',
value: tags,
value: isEmpty(tags) ? '-' : tags,
inline: true,
},
],
Expand All @@ -38,7 +33,7 @@ export const generateWaifuEmbed = (data: WaifuSchema): APIEmbed => {
};

export default {
commandType: 'Waifu',
commandType: 'Anime',
data: new SlashCommandBuilder().setName('waifu').setDescription('Shows a random waifu image'),
async execute({ interaction }: AppCommandOptions) {
try {
Expand Down
2 changes: 1 addition & 1 deletion src/events/ready/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function ({ app, appCommands }: EventModule) {
}
await sendBootNotification(app);
} catch (error) {
console.log(error);
sendErrorLog({ error });
}
});
}
58 changes: 58 additions & 0 deletions src/schemas/nekos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//Schemas for the nekosapi API
export interface NekosImageAPISchema {
data: NekosImageSchema[];
success: boolean;
}
export interface NekosImageSchema {
id: string;
url: string;
artist: NekosArtistSchema | null;
source: {
name: string | null;
url: string | null;
};
nsfw: boolean;
original: boolean | null;
categories: NekosCategorySchema[];
characters: NekosCharacterSchema[];
createdAt: string;
meta: NekosImageMeta;
}
export interface NekosArtistSchema {
id: string;
name: string;
url: string;
images: number;
}
export interface NekosCategorySchema {
id: string;
name: string;
description: string;
nsfw: boolean;
createdAt: string;
}
export interface NekosCharacterSchema {
id: string;
name: string;
description: string;
source: string;
gender: string;
ages: number[];
birth_date: string;
nationality: string;
occupations: string[];
createdAt: string;
}
export interface NekosImageMeta {
eTag: string;
size: number;
mimetype: string;
color: string;
expires: string;
dimens: {
width: number;
height: number;
aspectRatio: string;
orientation: string;
};
}
2 changes: 1 addition & 1 deletion src/schemas/waifu.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//Schemas for the waifu.im API; currently only for the GET /search endpoint
export interface WaifuAPI {
export interface WaifuAPISchema {
images: WaifuSchema[];
}
export interface WaifuSchema {
Expand Down
Loading