already existing character sheets can now be updated. Furthermore aliases are now conducted when trying to link feats/spells/actions

master
yun 2024-08-21 17:23:17 +02:00
parent e327c53390
commit 73ef5ef3fc
1 changed files with 102 additions and 67 deletions

115
main.ts
View File

@ -1,5 +1,5 @@
import * as Handlebars from 'handlebars'; import * as Handlebars from 'handlebars';
import { App, Vault, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, TAbstractFile } from 'obsidian'; import { App, Vault, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, TAbstractFile, TFile } from 'obsidian';
// Remember to rename these classes and interfaces! // Remember to rename these classes and interfaces!
@ -12,7 +12,7 @@ interface P2HLOSettings {
const DEFAULT_SETTINGS: P2HLOSettings = { const DEFAULT_SETTINGS: P2HLOSettings = {
userToken: '', userToken: '',
campaignToken: '', campaignToken: '',
notesFolder: '/' notesFolder: '/',
} }
const toolName = "p2hlo-bridge" const toolName = "p2hlo-bridge"
@ -38,6 +38,9 @@ interface convertReturn {
export default class P2HLO extends Plugin { export default class P2HLO extends Plugin {
settings: P2HLOSettings; settings: P2HLOSettings;
notes: { // mapping of a note by full filepath including file extension to its aliases
[filePath: string]: string[],
}
private byPrefixCode(obj: object, prefix: string) { private byPrefixCode(obj: object, prefix: string) {
return obj[Object.keys(obj).find( predicate => predicate.startsWith(prefix))] return obj[Object.keys(obj).find( predicate => predicate.startsWith(prefix))]
@ -52,7 +55,6 @@ export default class P2HLO extends Plugin {
}) })
} }
private prefixNumber(n: number) { private prefixNumber(n: number) {
if (n < 0) { if (n < 0) {
return `-${n}` return `-${n}`
@ -67,9 +69,27 @@ export default class P2HLO extends Plugin {
return str.replace(/\{b\}/gi, "**").replace(/\{\/b\}/gi, "**").replace(/\{br\}\{br\}/gi, "{br}").replace(/\{br\}/gi, "\\n") return str.replace(/\{b\}/gi, "**").replace(/\{\/b\}/gi, "**").replace(/\{br\}\{br\}/gi, "{br}").replace(/\{br\}/gi, "\\n")
} }
private makeLink(linkName: string, category: string = ""): string|undefined {
const sanitizedLinkName = linkName.replace("&#x27;", "'").toLowerCase().replace(/\ /g, "-")
console.log("finding link to ", sanitizedLinkName)
let found = undefined
const reName = new RegExp(`^${sanitizedLinkName}(?:-.{1,4})?\.md$`, "gi")
console.log("try to match", reName, category)
let fileName = ""
for (fileName in this.notes) {
if ((this.notes[fileName]??"").contains(linkName)) {
break;
}
}
if (fileName !== "") {
return fileName.split(".md")[0]
} else {
return undefined
}
}
convert(json: Object): convertReturn|null { private convert(json: Object): convertReturn|null {
const actor = this.byPrefixCode(json, "actor"); const actor = this.byPrefixCode(json, "actor");
@ -131,13 +151,13 @@ size: {{size}}
level: {{classes}} level: {{classes}}
trait_03: "Player" trait_03: "Player"
trait_04: "{{ancestry}}" trait_04: "{{ancestry}}"
languages: "{{#languages}}{{this}}, {{/languages}}; " languages: "{{#languages}} {{this}}, {{/languages}}; "
perception: perception:
- name: "Perception" - name: "Perception"
- desc: "Perception {{perception}}" desc: "Perception {{perception}}"
skills: skills:
- name: "Skills" - name: "Skills"
- desc: "{{#skills}}__{{name}}__: {{mod}} (1d20{{mod}}); {{/skills}}" desc: "{{#skills}}__{{name}}__: {{mod}} (1d20{{mod}}); {{/skills}}"
abilitiyMods: [{{str}}, {{con}}, {{dex}}, {{int}}, {{cha}}, {{wis}}] abilitiyMods: [{{str}}, {{con}}, {{dex}}, {{int}}, {{cha}}, {{wis}}]
abilities_top: abilities_top:
@ -155,6 +175,7 @@ abilities_bot:
armorclass: armorclass:
- name: AC - name: AC
desc: "{{ac}}; __Fort__: {{fortitude}} (1d20{{fortitude}}); __Ref__: {{reflex}} (1d20{{reflex}}); __Will__: {{will}} (1d20{{will}})" desc: "{{ac}}; __Fort__: {{fortitude}} (1d20{{fortitude}}); __Ref__: {{reflex}} (1d20{{reflex}}); __Will__: {{will}} (1d20{{will}})"
speed: "{{speeds}}" speed: "{{speeds}}"
attacks: attacks:
@ -221,7 +242,7 @@ attacks:
desc = predicate.name.split("(")[1].split(")")[0] desc = predicate.name.split("(")[1].split(")")[0]
} }
link = `compendium/feats/${name.trim().replace(/\ /g, "-")}` link = this.makeLink(name.trim(), "feats") ?? ""
if (predicate.actions) { if (predicate.actions) {
actionpoints = predicate.actions actionpoints = predicate.actions
@ -255,7 +276,7 @@ attacks:
desc = predicate.name.split("(")[1].split(")")[0] desc = predicate.name.split("(")[1].split(")")[0]
} }
link = `rules/actions/${name.trim().replace(/\ /g, "-")}` link = this.makeLink(name.trim(), "actions") ?? ""
if (predicate.actions) { if (predicate.actions) {
actionpoints = predicate.actions actionpoints = predicate.actions
@ -283,9 +304,7 @@ attacks:
}), }),
items: [...alchemicalItems, ...gear].map(predicate => { items: [...alchemicalItems, ...gear].map(predicate => {
let itemName = predicate.name let itemName = predicate.name
console.log(predicate.items)
if (predicate.items) { if (predicate.items) {
console.log(predicate.items, Object.values(predicate.items))
itemName += "(" itemName += "("
itemName += Object.values(predicate.items).map(predicate2 => "*" + predicate2.name + "*").join(", ") itemName += Object.values(predicate.items).map(predicate2 => "*" + predicate2.name + "*").join(", ")
itemName += ")" itemName += ")"
@ -311,8 +330,8 @@ attacks:
if (predicate.useInPlay) { if (predicate.useInPlay) {
desc = this.hloTextToMarkdown(predicate.useInPlay) desc = this.hloTextToMarkdown(predicate.useInPlay)
} }
console.log(name.trim())
let link = `compendium/spells/${predicate.name.trim()}` let link = this.makeLink(predicate.name.trim(), "spells") ?? ""
link = link.split(" (")[0] link = link.split(" (")[0]
link = link.replace(/\ /g, "-") link = link.replace(/\ /g, "-")
@ -420,21 +439,21 @@ attacks:
} }
async performTask() { async performTask() {
await this.precacheNotes()
console.log(this.notes)
if (await this.preflightTest()) { if (await this.preflightTest()) {
const accessToken = await this.fetchAccessToken() const accessToken = await this.fetchAccessToken()
const castMember = await this.fetchStage(accessToken) const castMember = await this.fetchStage(accessToken)
console.log(castMember)
if (castMember.length == 0) { if (castMember.length == 0) {
new Notice("No Castmember found on Stage. Did you forgot to start a session?") new Notice("No Castmember found on Stage. Did you forgot to start a session?")
return return
} }
const characters = await this.fetchCharacters(accessToken, castMember) const characters = await this.fetchCharacters(accessToken, castMember)
console.log(characters)
try { try {
const folder = this.app.vault.getFolderByPath(this.settings.notesFolder) const folder = this.app.vault.getFolderByPath(this.settings.notesFolder)
await this.app.vault.trash(folder as TAbstractFile, true) await this.app.fileManager.trashFile(folder as TAbstractFile)
} catch (e) { } catch (e) {
console.log(e) console.error(e)
} }
try { try {
await this.app.vault.createFolder(this.settings.notesFolder) await this.app.vault.createFolder(this.settings.notesFolder)
@ -448,12 +467,17 @@ attacks:
try { try {
await this.app.vault.create(`${this.settings.notesFolder}/${result.name}.md`, result.output) await this.app.vault.create(`${this.settings.notesFolder}/${result.name}.md`, result.output)
} catch (e) { } catch (e) {
const file = this.app.vault.getFileByPath(`/${this.settings.notesFolder}/${result.name}.md`) const directoryWithoutRoot = this.settings.notesFolder.substring(1)
const file = this.app.vault.getFileByPath(`${directoryWithoutRoot}/${result.name}.md`)
try {
if (file) { if (file) {
await this.app.vault.modify(file, result.output) await this.app.vault.modify(file, result.output)
} else { } else {
console.error(file) console.error(file)
} }
} catch (e) {
console.error(e)
}
} }
} }
} }
@ -461,21 +485,42 @@ attacks:
} }
} }
async getAliasesOfTFile(fileObject: TFile): Promise<string[]> {
return new Promise( (resolve, reject) => {
this.app.fileManager.processFrontMatter(
fileObject,
(frontMatter) => {
resolve(frontMatter.aliases)
}
)
})
}
private async precacheNotes() {
this.notes = {}
this.app.vault
.getMarkdownFiles()
.forEach(
async (fileObject: TFile) => {
this.notes[fileObject.path] = await this.getAliasesOfTFile(fileObject)
}
)
}
async onload() { async onload() {
await this.loadSettings(); await this.loadSettings()
// This creates an icon in the left ribbon. // This creates an icon in the left ribbon.
const ribbonIconEl = this.addRibbonIcon('dice', 'Sync Stage', async (evt: MouseEvent) => { const ribbonIconEl = this.addRibbonIcon('dot-network', 'Sync Stage', async (evt: MouseEvent) => {
// Called when the user clicks the icon. // Called when the user clicks the icon.
await this.performTask() await this.performTask()
}); })
// Perform additional things with the ribbon
ribbonIconEl.addClass('my-plugin-ribbon-class');
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
const statusBarItemEl = this.addStatusBarItem();
statusBarItemEl.setText('Status Bar Text');
// This adds a simple command that can be triggered anywhere // This adds a simple command that can be triggered anywhere
this.addCommand({ this.addCommand({
@ -484,19 +529,9 @@ attacks:
callback: () => { callback: () => {
this.preflightTest() this.preflightTest()
} }
}); })
// This adds a settings tab so the user can configure various aspects of the plugin this.addSettingTab(new P2HLOSettingTab(this.app, this))
this.addSettingTab(new SampleSettingTab(this.app, this));
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
// Using this function will automatically remove the event listener when this plugin is disabled.
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
console.log('click', evt);
});
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
} }
onunload() { onunload() {
@ -512,7 +547,7 @@ attacks:
} }
} }
class SampleSettingTab extends PluginSettingTab { class P2HLOSettingTab extends PluginSettingTab {
plugin: P2HLO; plugin: P2HLO;
constructor(app: App, plugin: P2HLO) { constructor(app: App, plugin: P2HLO) {