mirror of
https://github.com/tea0s/multimuse-tracker.git
synced 2026-07-22 06:56:41 +00:00
Command to create tracker
added a Initialize MultiMuse Workspace command to the plugin to allow easy setup of the tracker needed for the plugin
This commit is contained in:
parent
9dc2fca743
commit
430af632d5
5 changed files with 200 additions and 13 deletions
34
README.md
34
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 `<Scenes Folder>/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
|
||||
|
|
|
|||
171
main.ts
171
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<void> {
|
||||
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 `<Scenes Folder>/Roleplay Tracker.base` and saves that path.
|
||||
*/
|
||||
async initializeMultimuseWorkspace(): Promise<void> {
|
||||
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<void> {
|
||||
/**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 `<Scenes Folder>/Roleplay Tracker.base`.')
|
||||
.addText(text => text
|
||||
.setPlaceholder('RP Scenes/Roleplay Tracker.base')
|
||||
.setValue(this.plugin.settings.basePath)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue