11 Commits
0.3.3 ... 0.5.4

Author SHA1 Message Date
4dfa9b46cf bump version 2026-05-13 15:11:05 -05:00
34d426b617 change branch name 2026-05-13 15:03:56 -05:00
1187125335 bump version 2026-05-13 15:03:06 -05:00
e92f2890e1 fixes for v14 2026-05-13 15:01:48 -05:00
e7282a4b88 Fix template load bug and rename main script file
- Updated `module.json` to reflect version change from 0.5.2 to 0.5.3.
- Renamed `main.js` to `asc-session-title-suggestions.js` for better clarity and consistency.
- Modified script path in `module.json` to align with the new file name.
- Refactored template loading logic to consolidate into a single call, improving code readability.
2025-02-03 08:19:04 -06:00
333a4ab04e bump version 2024-11-24 18:43:49 -06:00
413d3715c7 added a "copy all" button 2024-11-24 18:32:48 -06:00
400c1c16ef update author, url 2024-06-28 13:38:14 -05:00
f321f956f7 echo version and download in zip script 2024-06-28 13:30:25 -05:00
879056f539 fix verified to latest verified version 2024-06-28 13:26:17 -05:00
e86ef0a8f3 update readme 2024-06-28 13:24:29 -05:00
7 changed files with 66 additions and 25 deletions

View File

@@ -2,12 +2,16 @@
## Overview ## Overview
This FoundryVTT module allows players to suggest titles for the session, similar to how podcast titles are suggested. In my own sessions, I record every session's audio and make it into a podcast. Many of my favorite podcasts use a random, funny, out-of-context quote from the episode for the title. Inspired by this, I created this module so players can suggest titles and the GM can list them all and choose the best one. Players can use the `/title` or `/t` command to suggest a title. A GM or trusted player can use the `/titles` or `/ts` command to get a list of all the suggestions for the most recent day's session. This FoundryVTT module allows players to suggest titles for the session, similar to how podcast titles are suggested. In my own sessions, I record every session's audio and make it into a podcast. Many of my favorite podcasts use a random, funny, out-of-context quote from the episode for the title. Inspired by this, I created this module so players can suggest titles and the GM can list them all and choose the best one. Players can use the `/title` or `/t` command to suggest a title. The GM (or other configurable role) can use the `/titles` or `/ts` command to get a list of all the suggestions for the most recent day's session.
## Example
![](screenshot.png)
## Features ## Features
- Players can suggest session titles using the `/title`, `/t`, or `t/` command. - Players can suggest session titles using the `/title`, `/t`, or `t/` command.
- GMs or trusted players can view all suggested titles for the most recent session using the `/titles` or `/ts` command. - GMs or trusted players can view all suggested titles for the most recent session using the `/titles` or `/ts` command. (Role is configurable in settings)
- Copy the titles using the clipboard icon button next to each suggestion in the list.
## Requirements ## Requirements

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

View File

@@ -1,2 +1,4 @@
git archive --format zip --output dist/module.zip master:src echo "version:"$(cat src/module.json|jq .version)
echo "download:"$(cat src/module.json|jq .download)
git archive --format zip --output dist/module.zip main:src
cp src/module.json dist/ cp src/module.json dist/

View File

@@ -2,6 +2,7 @@
"SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_HINT": "Select the minimum role required to use the /titles command.", "SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_HINT": "Select the minimum role required to use the /titles command.",
"SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_NAME": "List Titles Command Required Role", "SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_NAME": "List Titles Command Required Role",
"SESSION_TITLE_SUGGESTIONS.INVALID_DATE": "Invalid date provided.", "SESSION_TITLE_SUGGESTIONS.INVALID_DATE": "Invalid date provided.",
"SESSION_TITLE_SUGGESTIONS.NO_SUGGESTIONS": "No session title suggestions found.",
"SESSION_TITLE_SUGGESTIONS.SUGGESTION_AUTOCOMPLETE_MESSAGE": "Enter your session title suggestion.", "SESSION_TITLE_SUGGESTIONS.SUGGESTION_AUTOCOMPLETE_MESSAGE": "Enter your session title suggestion.",
"SESSION_TITLE_SUGGESTIONS.SUGGESTION_LIST_COMMAND_DESCRIPTION": "List all title suggestions for the provided date", "SESSION_TITLE_SUGGESTIONS.SUGGESTION_LIST_COMMAND_DESCRIPTION": "List all title suggestions for the provided date",
"SESSION_TITLE_SUGGESTIONS.SUGGESTION_COMMAND_DESCRIPTION": "Suggest a title for this session", "SESSION_TITLE_SUGGESTIONS.SUGGESTION_COMMAND_DESCRIPTION": "Suggest a title for this session",

View File

@@ -4,12 +4,14 @@
"description": "A simple module that keeps track of session title suggestions", "description": "A simple module that keeps track of session title suggestions",
"authors": [ "authors": [
{ {
"name": "lmxsdl" "name": "anthonyscorrea",
"url": "https://github.com/anthonyscorrea"
} }
], ],
"url": "https://github.com/anthonyscorrea/asc-session-title-suggestions",
"compatibility": { "compatibility": {
"minimum": "11", "minimum": "12",
"verified": ["11","12"] "verified": "14"
}, },
"languages": [ "languages": [
{ {
@@ -18,11 +20,11 @@
"path": "lang/en.json" "path": "lang/en.json"
} }
], ],
"download": "https://github.com/anthonyscorrea/asc-session-title-suggestions/releases/download/0.3.3/module.zip", "download": "https://github.com/anthonyscorrea/asc-session-title-suggestions/releases/download/0.5.4/module.zip",
"manifest": "https://github.com/anthonyscorrea/asc-session-title-suggestions/releases/latest/download/module.json", "manifest": "https://github.com/anthonyscorrea/asc-session-title-suggestions/releases/latest/download/module.json",
"version": "0.3.3", "version": "0.5.4",
"scripts": [ "scripts": [
"scripts/main.js" "scripts/asc-session-title-suggestions.js"
], ],
"esmodules":[ "esmodules":[
], ],

View File

@@ -1,3 +1,4 @@
const MODULE_ID = "asc-session-title-suggestions"
const NAME = "/title" const NAME = "/title"
const template_path = "modules/asc-session-title-suggestions/templates" const template_path = "modules/asc-session-title-suggestions/templates"
@@ -13,9 +14,30 @@ const TEMPLATES = {
} }
} }
function getSuggestionTitle(message) {
return message.getFlag?.(MODULE_ID, "session_title_suggestion")
?? message.flags?.[MODULE_ID]?.session_title_suggestion
?? message.flags?.session_title_suggestion
}
function getSuggestionDate(message) {
return new Date(message.timestamp)
}
function toSuggestionViewData(message) {
return {
title: getSuggestionTitle(message),
userName: message.user?.name ?? message.author?.name ?? game.users.get(message.userId)?.name ?? "",
timestamp: message.timestamp
}
}
function registerClipboardCopyButton() { function registerClipboardCopyButton() {
copyToClipboardListener = (event) => { copyToClipboardListener = (event) => {
const text=event.target.dataset.clipboardText; let text=event.target.dataset.clipboardText;
if (text.includes(';;;')){
text = text.split(';;;').join('\n')
}
console.log(`Session Title Suggestions | Copying "${text}" to clipboard`); console.log(`Session Title Suggestions | Copying "${text}" to clipboard`);
navigator.clipboard.writeText(text) navigator.clipboard.writeText(text)
} }
@@ -36,7 +58,11 @@ function registerCustomChatCommands() {
const newMessageData = {} const newMessageData = {}
newMessageData.content = await renderTemplate(TEMPLATES.suggestion.content, {content:titleSuggestion}) newMessageData.content = await renderTemplate(TEMPLATES.suggestion.content, {content:titleSuggestion})
newMessageData.flavor = await renderTemplate(TEMPLATES.suggestion.flavor) newMessageData.flavor = await renderTemplate(TEMPLATES.suggestion.flavor)
newMessageData.flags = {session_title_suggestion: titleSuggestion} newMessageData.flags = {
[MODULE_ID]: {
session_title_suggestion: titleSuggestion
}
}
return newMessageData; return newMessageData;
}, },
autocompleteCallback: (menu, alias, parameters) => [ autocompleteCallback: (menu, alias, parameters) => [
@@ -55,34 +81,38 @@ function registerCustomChatCommands() {
callback: async (chat, parameters, messageData) => { callback: async (chat, parameters, messageData) => {
const newMessageData = {} const newMessageData = {}
const suggestions = game.messages.filter(m => { const suggestions = game.messages.filter(m => {
return m.flags.session_title_suggestion return getSuggestionTitle(m)
}) })
if (!suggestions.length) {
ui.notifications.warn(game.i18n.localize("SESSION_TITLE_SUGGESTIONS.NO_SUGGESTIONS") || "No session title suggestions found.");
return;
}
let selected_message_date let selected_message_date
if (!parameters) { if (!parameters) {
selected_message_date = new Date(suggestions[suggestions.length-1].timestamp) selected_message_date = getSuggestionDate(suggestions[suggestions.length-1])
} else { } else {
const epoch_date = Date.parse(parameters) const epoch_date = Date.parse(parameters)
if (Number.isNaN(epoch_date)){ if (Number.isNaN(epoch_date)){
ui.notifications.error(`${game.i18n.localize("SESSION_TITLE_SUGGESTIONS.INVALID_DATE")} (${parameter})`); ui.notifications.error(`${game.i18n.localize("SESSION_TITLE_SUGGESTIONS.INVALID_DATE")} (${parameters})`);
return; return;
} }
selected_message_date = new Date(epoch_date) selected_message_date = new Date(epoch_date)
} }
const filtered_suggestions = suggestions.filter(m=>{ const filtered_suggestions = suggestions.filter(m=>{
const message_date = new Date(m.timestamp) const message_date = getSuggestionDate(m)
return message_date.toDateString() == selected_message_date.toDateString() return message_date.toDateString() == selected_message_date.toDateString()
}) }).map(toSuggestionViewData)
newMessageData.content = await renderTemplate(TEMPLATES.suggestionList.content, {messages:filtered_suggestions }) newMessageData.content = await renderTemplate(TEMPLATES.suggestionList.content, {messages:filtered_suggestions })
newMessageData.flavor = await renderTemplate(TEMPLATES.suggestionList.flavor, {date:selected_message_date.toDateString()}) newMessageData.flavor = await renderTemplate(TEMPLATES.suggestionList.flavor, {date:selected_message_date.toDateString()})
return newMessageData; return newMessageData;
}, },
autocompleteCallback: (menu, alias, parameters) => { autocompleteCallback: (menu, alias, parameters) => {
const suggestions = game.messages.filter(m => { const suggestions = game.messages.filter(m => {
return m.flags.session_title_suggestion return getSuggestionTitle(m)
}) })
const dates = new Set( const dates = new Set(
suggestions.map(s=>new Date(s.timestamp).toDateString()) suggestions.map(s=>getSuggestionDate(s).toDateString())
) )
const entries = [...dates].map(date=>{ const entries = [...dates].map(date=>{
return game.chatCommands.createCommandElement(`${alias} ${date}`, date) return game.chatCommands.createCommandElement(`${alias} ${date}`, date)
@@ -98,8 +128,10 @@ function registerCustomChatCommands() {
Hooks.on("init", function() { Hooks.on("init", function() {
//This code runs once the Foundry VTT software begins its initialization workflow //This code runs once the Foundry VTT software begins its initialization workflow
registerClipboardCopyButton(); registerClipboardCopyButton();
Object.values(TEMPLATES.suggestion).forEach((template_path)=>loadTemplates(template_path)) loadTemplates([
Object.values(TEMPLATES.suggestionList).forEach((template_path)=>loadTemplates(template_path)) ...Object.values(TEMPLATES.suggestion),
...Object.values(TEMPLATES.suggestionList)
])
game.settings.register("asc-session-title-suggestions", "titleListCommandRole", { game.settings.register("asc-session-title-suggestions", "titleListCommandRole", {
name: game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_NAME"), name: game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_NAME"),
scope: "world", scope: "world",
@@ -115,7 +147,7 @@ Hooks.on("init", function() {
}, },
hint: game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_HINT") hint: game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_HINT")
}); });
import ('https://cdn.jsdelivr.net/npm/title-case@4.3.1/dist/index.min.js') import ('https://cdn.jsdelivr.net/npm/title-case@4.3.2/dist/index.min.js')
.then((module)=>{console.log('asc','loading...');Handlebars.registerHelper("titlecase", module.titleCase)}) .then((module)=>{console.log('asc','loading...');Handlebars.registerHelper("titlecase", module.titleCase)})
}); });

View File

@@ -1,3 +1,3 @@
<ul>{{~#each messages ~}} <ul>{{~#each messages ~}}
<li><a class="fa-regular fa-clipboard clipboard" style="padding-left:.5em;padding-right:.5em;" data-clipboard-text="{{titlecase this.flags.session_title_suggestion}}"></a><i>"{{titlecase this.flags.session_title_suggestion}}"</i> - {{this.user.name}}</li> <li><a class="fa-regular fa-clipboard clipboard" style="padding-left:.5em;padding-right:.5em;" data-clipboard-text="{{titlecase this.title}}"></a><i>"{{titlecase this.title}}"</i> - {{this.userName}}</li>
{{~/each~}}</ul> {{~/each~}}</ul><a class="fa-regular fa-clipboard clipboard" style="padding-left:.5em;padding-right:.5em;" data-clipboard-text="{{#each messages}}- _&quot;{{titlecase this.title}}&quot;_ - {{this.userName}}&#10;{{/each}}"></a> Copy All