From 430af632d56e4a3fd10595cef137dfeae8047535 Mon Sep 17 00:00:00 2001 From: Tea Date: Sat, 16 May 2026 12:52:16 -0400 Subject: [PATCH] Command to create tracker added a Initialize MultiMuse Workspace command to the plugin to allow easy setup of the tracker needed for the plugin --- README.md | 34 ++++++--- main.ts | 171 +++++++++++++++++++++++++++++++++++++++++++++- manifest.json | 2 +- package-lock.json | 4 +- package.json | 2 +- 5 files changed, 200 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 2efd51f..c368abf 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,10 @@ An Obsidian plugin for seamless integration with the MultiMuse Discord bot. Trac ## Installation -### Manual Installation +Install via the Obsidian plugin library + + +OR Install via [BRAT](https://obsidian.md/plugins?id=obsidian42-brat) with https://github.com/BackstagePassGroup/multimuse-obsidian @@ -33,13 +36,27 @@ Install via [BRAT](https://obsidian.md/plugins?id=obsidian42-brat) with https:// 1. Open Obsidian Settings → Multimuse Tracker 2. Paste your API key in the "API Key" field 3. Your Discord user ID will be automatically detected from the API key -4. Configure other settings: - - **Enable Polling**: Turn automatic checking on/off - - **Poll Interval**: How often to check for new replies (5-60 minutes) - - **Scenes Folder**: Folder containing your scene files (default: "RP Scenes") - - **Obsidian Base Path**: Optional path to Base file for scene tracking - - **Track Roleplay Property**: Automatically extract "Roleplay" from folder path - - **Track Is Active? Property**: Automatically add "Is Active?" property (defaults to true) +4. Adjust paths and property toggles if you want something other than the defaults: + - **Scenes Folder**: Where scene notes live (default: `RP Scenes`) + - **Track Roleplay Property** / **Track Is Active? Property**: Match how you want new scenes to get frontmatter (defaults on) + - **Obsidian Base Path**: Optional. Leave empty for first-time setup (see below), or set to a `.base` or `.md` file you already use + - **Enable Polling** / **Poll Interval**: How often threads are checked + +### 3. First-time vault layout (recommended) + +Use a single command to create your scenes folder and a Base aligned with your settings: + +1. Open the Command Palette and run **Initialize MultiMuse workspace** +2. The plugin will: + - Create your **Scenes Folder** in the vault if it does not exist yet + - If **Obsidian Base Path** is empty, create `/MultiMuse Scenes.base` (native Obsidian Base) and save that path in settings + - If **Obsidian Base Path** is set to a path ending in `.base` or `.md` that does not exist yet, create that file instead and keep the path as configured + +**Native `.base` file:** The generated Base lists markdown files under your scenes folder, filters to **Is Active?** = true when that property toggle is on, and shows columns for `Link`, `Characters`, optional `Roleplay` / `Is Active?`, `Participants`, `Replied?`, and `Created`. Requires an Obsidian version that supports **Bases**. + +**Markdown `.md` tracker:** If your Base path ends in `.md`, the command creates a starter pipe table. The plugin can append rows to that table when you create or sync scenes (it does not edit `.base` files programmatically; use the Base UI for those). + +You can run **Initialize MultiMuse workspace** again only after removing or renaming the target file, or after changing **Obsidian Base Path**. ## Usage @@ -100,6 +117,7 @@ Created: 2024-01-15 ## Commands +- **Initialize MultiMuse workspace**: Create your **Scenes Folder** and a Base (`.base`) or markdown tracker (`.md`) from settings; sets **Obsidian Base Path** when you start with it empty - **Check Discord Threads Now**: Manually trigger a check for all scenes - **Toggle Discord Polling**: Enable/disable automatic polling - **Create New Scene**: Create a new scene file with muse selection diff --git a/main.ts b/main.ts index 71f83ed..f0ee4b3 100644 --- a/main.ts +++ b/main.ts @@ -183,6 +183,15 @@ export default class MultimuseObsidian extends Plugin { } }); + // First-time vault layout: scenes folder + Base (.base or .md) from settings + this.addCommand({ + id: 'initialize-multimuse-workspace', + name: 'Initialize MultiMuse workspace', + callback: () => { + void this.initializeMultimuseWorkspace(); + } + }); + // Add command to insert Discord @ mention (guild members from Link property) this.addCommand({ id: 'insert-mention', @@ -1479,6 +1488,166 @@ export default class MultimuseObsidian extends Plugin { // ========= BASE INTEGRATION ========= + /** Ensure each segment of `folderPath` exists under the vault root. */ + async ensureFolderPathExists(folderPath: string): Promise { + const normalized = folderPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, ''); + if (!normalized) return; + const parts = normalized.split('/').filter((p) => p.length > 0); + let acc = ''; + for (const part of parts) { + acc = acc ? `${acc}/${part}` : part; + const existing = this.app.vault.getAbstractFileByPath(acc); + if (!existing) { + await this.app.vault.createFolder(acc); + } + } + } + + /** + * YAML for a native Obsidian Base listing scene notes under the scenes folder, + * with columns aligned to MultiMuse frontmatter and plugin toggles. + */ + buildSceneBaseYaml(scenesFolder: string): string { + const folderLit = JSON.stringify(scenesFolder); + const lines: string[] = [ + '# MultiMuse Tracker — generated Base (safe to edit in Obsidian)', + 'filters:', + ' and:', + ' - file.ext == "md"', + ` - file.inFolder(${folderLit})`, + ]; + if (this.settings.trackIsActive) { + lines.push(' - \'note["Is Active?"] == true\''); + } + lines.push( + 'properties:', + ' file.name:', + ' displayName: Scene', + ' file.path:', + ' displayName: Path', + ' Link:', + ' displayName: Link', + ' Characters:', + ' displayName: Characters', + ); + if (this.settings.trackRoleplay) { + lines.push(' Roleplay:', ' displayName: Roleplay'); + } + lines.push( + ' Participants:', + ' displayName: Participants', + " 'Replied?':", + ' displayName: Replied?', + ); + if (this.settings.trackIsActive) { + lines.push(" 'Is Active?':", ' displayName: Is Active?'); + } + lines.push( + ' Created:', + ' displayName: Created', + 'views:', + ' - type: table', + ' name: Roleplay Tracker', + ' order:', + ' - file.name', + ' - Link', + ' - Characters', + ); + if (this.settings.trackRoleplay) { + lines.push(' - Roleplay'); + } + lines.push( + ' - Participants', + " - 'Replied?'", + ); + if (this.settings.trackIsActive) { + lines.push(" - 'Is Active?'"); + } + lines.push(' - Created'); + return lines.join('\n') + '\n'; + } + + /** Starter markdown table compatible with this plugin's markdown Base integration. */ + buildMarkdownTrackerStub(): string { + return [ + '# MultiMuse scene tracker', + '', + 'Rows below are appended when you create or sync scenes if **Obsidian Base Path** points to this file.', + '', + '| Scene | Characters | Link | Participants | Replied? |', + '|-------|------------|------|--------------|----------|', + '', + ].join('\n'); + } + + /** + * Create the configured scenes folder (if missing), then a new Base or markdown tracker file. + * If **Obsidian Base Path** is empty, creates `/Roleplay Tracker.base` and saves that path. + */ + async initializeMultimuseWorkspace(): Promise { + const scenesFolder = this.settings.scenesFolder + .trim() + .replace(/\\/g, '/') + .replace(/^\/+|\/+$/g, ''); + if (!scenesFolder) { + new Notice('Set Scenes Folder in Multimuse Tracker settings first.'); + return; + } + + const configuredBase = this.settings.basePath + .trim() + .replace(/\\/g, '/') + .replace(/^\/+|\/+$/g, ''); + + let targetBasePath: string; + if (!configuredBase) { + targetBasePath = `${scenesFolder}/Roleplay Tracker.base`; + } else { + targetBasePath = configuredBase; + } + + const ext = (targetBasePath.split('.').pop() || '').toLowerCase(); + if (ext !== 'base' && ext !== 'md') { + new Notice('Obsidian Base Path must end in .base or .md, or leave it empty to create Roleplay Tracker.base under your scenes folder.'); + return; + } + + try { + await this.ensureFolderPathExists(scenesFolder); + + const existing = this.app.vault.getAbstractFileByPath(targetBasePath); + if (existing) { + new Notice(`Already exists: ${targetBasePath}. Remove it or change Obsidian Base Path in settings, then run again.`); + return; + } + + const parent = targetBasePath.includes('/') + ? targetBasePath.slice(0, targetBasePath.lastIndexOf('/')) + : ''; + if (parent) { + await this.ensureFolderPathExists(parent); + } + + const body = ext === 'base' + ? this.buildSceneBaseYaml(scenesFolder) + : this.buildMarkdownTrackerStub(); + + await this.app.vault.create(targetBasePath, body); + + this.settings.basePath = targetBasePath; + await this.saveSettings(); + + new Notice( + ext === 'base' + ? `Created Base and set path: ${targetBasePath}` + : `Created markdown tracker and set path: ${targetBasePath}`, + ); + } catch (error) { + console.error('[MultimuseObsidian] initializeMultimuseWorkspace:', error); + new Notice(`Could not initialize workspace: ${getErrorMessage(error)}`); + } + } + async addSceneToBase(file: TFile, frontmatter: FrontmatterData): Promise { /**Add scene to Obsidian Base with characters as variables.*/ if (!this.settings.basePath) return; @@ -2061,7 +2230,7 @@ class MultimuseObsidianSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Obsidian Base Path') - .setDesc('Path to your Obsidian Base file (e.g., "RP Scenes/Roleplay Tracker.base" or "RP Scenes/Tracker.md")') + .setDesc('Path to your Obsidian Base file (e.g., "RP Scenes/Roleplay Tracker.base" or "RP Scenes/Tracker.md"). Leave empty and run **Initialize MultiMuse workspace** to create `/Roleplay Tracker.base`.') .addText(text => text .setPlaceholder('RP Scenes/Roleplay Tracker.base') .setValue(this.plugin.settings.basePath) diff --git a/manifest.json b/manifest.json index 6addfeb..9cc76fb 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "multimuse-tracker", "name": "Multimuse Tracker", - "version": "1.10.1", + "version": "1.11.0", "minAppVersion": "1.4.0", "description": "Roleplay sync tool for use with the MultiMuse bot in discord.", "author": "BackstagePass Group", diff --git a/package-lock.json b/package-lock.json index d195ff9..2653dda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "multimuse-tracker", - "version": "1.10.1", + "version": "1.11.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "multimuse-tracker", - "version": "1.10.1", + "version": "1.11.0", "license": "MIT", "devDependencies": { "@types/node": "^16.11.6", diff --git a/package.json b/package.json index 0778f55..f079ea0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "multimuse-tracker", - "version": "1.10.1", + "version": "1.11.0", "description": "MultiMuse bot integration for tracking Discord threads and sending messages as muses", "main": "main.js", "scripts": {