Skip to content
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

Wordcloud fonts #32

Merged
merged 2 commits into from
Mar 23, 2024
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
6 changes: 5 additions & 1 deletion commands/wordcloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ module.exports = {
.setDescription('Generate a colorful wordcloud from your server\'s quotes!')
.addStringOption(option =>
option.setName('author')
.setDescription('Generate a wordcloud from a specific author')
.setDescription('Generate a wordcloud for a specific author.')
.setRequired(false))
.addStringOption(option =>
option.setName('font')
.setDescription('The font to use. Defaults to one of Georgia, Rockwell, Century Gothic, or Trebuchet MS.')
.setRequired(false)),
async execute (interaction, guildManager) {
await interactionHandlers.wordcloudHandler(interaction);
Expand Down
17 changes: 12 additions & 5 deletions modules/interaction-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,25 +205,32 @@ module.exports = {
.sort((a, b) => a.frequency >= b.frequency ? -1 : 1)
.slice(0, constants.MAX_WORDCLOUD_WORDS),
constants.WORDCLOUD_SIZE,
nodeDocument
nodeDocument,
interaction.options.getString('font')?.toLowerCase().trim()
);
initializationResult.cloud.on('end', () => {
const d3 = constructor.draw(
initializationResult.cloud,
initializationResult.words,
nodeDocument.body
nodeDocument.body,
interaction.options.getString('font')?.toLowerCase().trim()
);
const buffer = Buffer.from(d3.select(nodeDocument.body).node().innerHTML.toString());
sharp(buffer)
.resize(constants.WORDCLOUD_SIZE, constants.WORDCLOUD_SIZE)
.png()
.toBuffer()
.then(async data => {
let content = author && author.length > 0
? 'Here\'s a wordcloud for quotes said by "' + author + '"!'
: 'Here\'s a wordcloud I generated from this server\'s quotes!';
if (interaction.options.getString('font')
&& !constructor.CONFIG.FONTS[interaction.options.getString('font')?.toLowerCase().trim()]) {
content += ' I couldn\'t use the font you wanted, though. Reference supported fonts using `/help`.';
}
await interaction.followUp({
files: [new AttachmentBuilder(data, { name: 'wordcloud.png' })],
content: author && author.length > 0
? 'Here\'s a wordcloud for quotes said by "' + author + '"!'
: 'Here\'s a wordcloud I generated from this server\'s quotes!'
content
});
})
.catch(async err => {
Expand Down
36 changes: 19 additions & 17 deletions modules/response-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,30 @@ module.exports = {
' You can either narrow your search, or you can always download saved quotes using the `/download` command.',
GENERIC_INTERACTION_ERROR: 'There was an error while executing this command! Feel free to contact the developer using' +
' info found with the `/help` commmand.',
HELP_MESSAGE: '\n\n**About:**\n\nThis is a bot for adding quotes and revisiting them later. To get the latest info on ' +
HELP_MESSAGE: 'To get the latest info on ' +
'changes to the bot, use the `/updates` command.\n\n' +
'Add a quote with `/add`. The author can be a mention of a user in the server (e.g. @Bob) or simply a name (Bob). You ' +
'do not need to wrap the quote in quotation marks. If the quote was said before today, you can optionally provide a "date" parameter (MM/DD/YYYY or MM-DD-YYYY)\n\n' +
'Find quotes with `/search`. You can enter a word or phrase, and the bot will give you the quotes that match.\n\n' +
'Pull random quotes with `/random`.\n\n' +
'You can receive all the quotes you have saved at any time using `/download`. You can also get a list of authors using `/authors`.\n\n' +
'To `/delete` a quote, you must first use the `/search` command with the `include_identifier` ' +
'option as `true`. This will return an integer ID for the quote. Then, provide that ID to the delete command' +
' (I am open to suggestions on how to make the deletion process easier).\n\n' +
'You can also generate a "wordcloud" visualization of quotes said in your server using `/wordcloud`.\n\n' +
'`/add` - Add a quote. The author can be a mention of a user in the server (e.g. @Bob) or simply a name (Bob). You ' +
'do not need to wrap the quote in quotation marks. If the quote was said before today, you can optionally provide a "date" parameter (MM/DD/YYYY or MM-DD-YYYY).\n' +
'`/search` - Find quotes that match a word or phrase.\n' +
'`/random` - Pull a random quote, optionally by a specific author.\n' +
'`/download` - Receive all the quotes you have saved as a text file.\n' +
'`/authors` - Receive a list of all unique authors of saved quotes.\n' +
'`/count` - See how many quotes have been saved.\n' +
'`/delete` - Remove a quote by providing its numerical identifier. The identifier can be obtained by using the `/search` command with the `include_identifier` ' +
'option as `true`.\n' +
'`/wordcloud` - Generate a wordcloud visualization of quotes said in your server. This includes ' +
'options to use a specific author\'s quotes and to use your choice of font. By default, the font will be one of ' +
'Georgia, Rockwell, Century Gothic, or Trebuchet MS. Additional supported fonts include Arial, Verdana, Tahoma, ' +
'Impact, Times New Roman, Baskerville, Courier, Comic Sans, Calibri, Consolas, and Segoe UI.\n\n' +
'**Privacy Policy:**\n\n' +
'Quotes added in a particular server can only be retrieved by users in that server. ' +
'The bot uses an SSL connection to store your quotes in a password-protected database. Only the bot and its ' +
'creator have access. Quotes (but not the names of their authors) are stored with encryption. The data is only' +
' used for this bot and its associated commands. Obviously, the quotes you add are a reflection of you and your server.' +
' For safety, the bot will not accept quotes that produce hyperlinks, but other than that, it does not attempt ' +
'The bot stores quotes in a secure database to which only the bot and its creator have access. The data is only' +
' used for this bot and its associated commands. For safety, the bot will not accept quotes that produce hyperlinks, but other than that, it does not attempt ' +
'to moderate quote content. Quote content moderation is thus only about as good as your server\'s moderation.\n\n' +
'**Support:**\n\nFor questions or concerns, you can e-mail the creator at leohfx@gmail.com. Thanks so much for using my bot! :) ' +
'I hope it serves as a nice tool to preserve good memories.\n\n' +
'**Support:**\n\nFor questions or concerns, you can e-mail the creator at quote.bot.contact@gmail.com. Thanks so much for using my bot! :)\n\n' +
'This bot is open source! Find it at: <https://github.com/AlecM33/quote-bot>',
UPDATES_MESSAGE: '**Latest Updates**\n\n**v1.0.2** (11 March 2024)\n- Fixed a bug that prevented the `/authors` command ' +
UPDATES_MESSAGE: '**Latest Updates**\n\n**v1.1.0 - Changes to /wordcloud** (23 March 2024)\n- the wordcloud command now supports a "font" option with several choices. Reference those using the ' +
'/help command. To improve consistency in the visual output, the "size" option has been removed in favor of a single standard size. \n\n**v1.0.2** (11 March 2024)\n- Fixed a bug that prevented the `/authors` command ' +
'from working if the bot\'s reply would exceed Discord\'s maximum message length. Now, if this would be the case, it will attach ' +
'the authors as a file instead. \n\n**1000 quotes!** (28 December 2023)\n- This bot is now storing over 1000 ' +
'quotes from several dozen servers. Cheers to the new year and happy quoting!\n\n**v1.0.1** (7 November 2023)\n-' +
Expand Down
45 changes: 39 additions & 6 deletions modules/wordcloud-constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,42 @@ const CONFIG = {
MIN_FONT_SIZE: 25,
MAX_FONT_SIZE: 100,
WORD_PADDING: 5,
WORD_ROTATION: 0,
COLORS: null
WORD_ROTATION: () => { return 0; },
COLORS: null,
FONTS: {
arial: 'Arial',
verdana: 'Verdana',
tahoma: 'Tahoma',
'trebuchet ms': 'Trebuchet MS',
trebuchet: 'Trebuchet MS',
impact: 'Impact',
'times new roman': 'Times New Roman',
times: 'Times New Roman',
georgia: 'Georgia',
baskerville: 'Baskerville Old Face',
'baskerville old face': 'Baskerville Old Face',
courier: 'Courier New',
'courier new': 'Courier New',
'comic sans': 'Comic Sans MS',
'comic sans ms': 'Comic Sans MS',
calibri: 'Calibri',
'century gothic': 'Century Gothic',
consolas: 'Consolas',
rockwell: 'Rockwell',
'segoe ui': 'Segoe UI',
segoe: 'Segoe UI'
},
DEFAULT_FONTS: [
'Century Gothic',
'Rockwell',
'Georgia',
'Trebuchet MS'
]
};

module.exports = import('d3').then((d3) => {
return {
initialize: (wordsWithOccurrences, size, nodeDocument) => {
initialize: (wordsWithOccurrences, size, nodeDocument, font) => {
const wordcloud = cloud();
CONFIG.COLORS = randomColor({
luminosity: 'light',
Expand All @@ -30,6 +59,8 @@ module.exports = import('d3').then((d3) => {
.padding(CONFIG.WORD_PADDING)
.rotate(CONFIG.WORD_ROTATION)
.timeInterval(10)
.font(CONFIG.FONTS[font] || CONFIG.DEFAULT_FONTS[
Math.floor(Math.random() * CONFIG.DEFAULT_FONTS.length)])
.canvas(() => nodeDocument.createElement('canvas'))
.fontSize(function (d) {
return d.size;
Expand All @@ -38,7 +69,7 @@ module.exports = import('d3').then((d3) => {
return { cloud: wordcloud, words: wordsWithOccurrences, config: CONFIG };
},

draw: (wordcloud, words, element) => {
draw: (wordcloud, words, element, font) => {
d3.select(element).append('svg')
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr('width', wordcloud.size()[0])
Expand All @@ -53,7 +84,8 @@ module.exports = import('d3').then((d3) => {
.style('font-size', function (d) {
return d.size + 'px';
})
.style('font-family', 'Georgia')
.style('font-family', CONFIG.FONTS[font] || CONFIG.DEFAULT_FONTS[
Math.floor(Math.random() * CONFIG.DEFAULT_FONTS.length)])
.style('fill', () => {
return CONFIG.COLORS[Math.floor(Math.random() * CONFIG.COLORS.length)];
})
Expand All @@ -66,6 +98,7 @@ module.exports = import('d3').then((d3) => {
});

return d3;
}
},
CONFIG
};
});