mudnug_note-reader/main.js
2026-05-28 12:54:04 -06:00

396 lines
No EOL
13 KiB
JavaScript

var LogLevel = {
DEBUG: 3,
ERROR: 0,
INFO: 2,
TRACE: 4,
WARN: 1
};
var ContextualLogger = class {
constructor(logger, component, operation) {
this.logger = logger;
this.component = component;
this.operation = operation;
}
debug(message, context) {
this.logger.debug(message, this.getContext(context));
}
error(message, context) {
this.logger.error(message, this.getContext(context));
}
errorFromException(message, error, context) {
this.logger.errorFromException(message, error, this.getContext(context));
}
handleError(message, error, context, shouldThrow = false) {
this.logger.handleError(message, error, this.getContext(context), shouldThrow);
}
info(message, context) {
this.logger.info(message, this.getContext(context));
}
trace(message, context) {
this.logger.trace(message, this.getContext(context));
}
warn(message, context) {
this.logger.warn(message, this.getContext(context));
}
getContext(additionalContext) {
return {
component: additionalContext?.component || this.component,
operation: additionalContext?.operation || this.operation,
...additionalContext
};
}
};
var Logger = class _Logger {
static instance;
logLevel = LogLevel.ERROR;
constructor(settings) {
this.updateSettings(settings);
}
static getInstance(settings) {
if (!_Logger.instance) {
_Logger.instance = new _Logger(settings);
} else {
_Logger.instance.updateSettings(settings);
}
return _Logger.instance;
}
debug(message, context) {
this.log(LogLevel.DEBUG, message, context);
}
error(message, context) {
this.log(LogLevel.ERROR, message, context);
}
errorFromException(message, error, context) {
this.error(message, { ...context, error });
}
forComponent(component) {
return new ContextualLogger(this, component);
}
forOperation(operation) {
return new ContextualLogger(this, void 0, operation);
}
handleError(message, error, context, shouldThrow = false) {
this.error(message, { ...context, error });
if (shouldThrow && error) {
throw error;
}
}
info(message, context) {
this.log(LogLevel.INFO, message, context);
}
trace(message, context) {
this.log(LogLevel.TRACE, message, context);
}
updateSettings(settings) {
this.logLevel = settings.troubleshooting.debugLogging ? LogLevel.DEBUG : LogLevel.WARN;
}
warn(message, context) {
this.log(LogLevel.WARN, message, context);
}
formatMessage(message, context) {
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[1];
const component = context?.component || "NoteReader";
const operation = context?.operation ? `:${context.operation}` : "";
let formattedMessage = `[${timestamp}] [${component}${operation}] ${message}`;
if (context?.metadata && Object.keys(context.metadata).length > 0) {
formattedMessage += ` | ${JSON.stringify(context.metadata)}`;
}
return formattedMessage + "\n";
}
log(level, message, context) {
if (!this.shouldLog(level)) {
return;
}
const formattedMessage = this.formatMessage(message, context);
switch (level) {
case LogLevel.ERROR:
console.error(formattedMessage, context?.error || "");
break;
case LogLevel.WARN:
console.warn(formattedMessage);
break;
case LogLevel.INFO:
console.log(formattedMessage);
break;
case LogLevel.DEBUG:
case LogLevel.TRACE:
console.debug(formattedMessage);
break;
}
}
shouldLog(level) {
return level <= this.logLevel;
}
};
// src/settings/SettingsData.ts
var DEFAULT_SETTINGS = {
filters: {
asterisks: true,
backslashEscapes: true,
codeBlocks: true,
emojis: true,
enablePhraseLineFilter: false,
frontmatter: true,
headers: true,
highlights: true,
ignorePhraseLine: "",
imageEmbeds: true,
inlineCode: true,
tables: false,
tags: false,
underscores: true,
urls: true
},
liteMode: false,
onboarding: {
hasShownMobileBatteryNotice: false,
hasShownOnboardingTooltip: false
},
reading: {
alwaysStartFromBeginningOnModify: false,
enablePositionPersistence: false,
enableReadFileName: false,
persistRewind: true,
repeatReaderCommand: "pause" /* PAUSE */,
repeatReaderCommandNewNoteVisible: "reload" /* RELOAD */,
resumeThresholdSeconds: 60
},
readingCompletionBehavior: {
closePlayerOnFinish: true,
enableChimeOnFinish: true,
enableStopReading: false,
stopReadingPhrase: ""
},
showRibbonIcon: true,
stats: {
generatedAudioFileCount: 0,
playSampleTextCounter: 0,
readNoteCount: 0,
readTotalSeconds: 0,
restartFromBeginningCount: 0,
selectCloseCount: 0,
selectPauseCount: 0,
selectPlayCount: 0,
selectReloadCount: 0,
selectRewindCount: 0,
viewSettingsCount: 0
},
storage: {
audioFileStorageLocation: "subfolder" /* SUBFOLDER */,
specifiedFolderPath: "",
subfolderName: "note-readings"
},
troubleshooting: {
debugLogging: false,
readActiveNoteOnLoad: false,
showEstimatedReadingTime: false,
stallCheckIntervalMs: 2e3,
stallThresholdSeconds: 5,
targetBufferAheadSeconds: 90
},
tts: {
pitch: 0,
provider: "online",
speed: 1,
voiceLocal: "Microsoft Zira - English (United States)",
voiceOnline: "en-US-AvaMultilingualNeural",
voiceSelectorFilters: null
},
wordHighlighting: {
customThemes: [],
enableLockedScrolling: true,
enableWordHighlighting: true,
highlightThemeId: "classy"
}
};
var SettingsManager = class _SettingsManager {
constructor(settings) {
this.settings = settings;
this.logger = Logger.getInstance(settings).forComponent(this.constructor.name);
}
logger;
static loadSettings(data) {
if (!data || typeof data !== "object") {
return DEFAULT_SETTINGS;
}
const rawData = data;
const settings = {
...DEFAULT_SETTINGS,
...rawData,
filters: { ...DEFAULT_SETTINGS.filters, ...rawData.filters },
onboarding: { ...DEFAULT_SETTINGS.onboarding, ...rawData.onboarding },
reading: { ...DEFAULT_SETTINGS.reading, ...rawData.reading },
readingCompletionBehavior: { ...DEFAULT_SETTINGS.readingCompletionBehavior, ...rawData.readingCompletionBehavior },
stats: { ...DEFAULT_SETTINGS.stats, ...rawData.stats },
storage: { ...DEFAULT_SETTINGS.storage, ...rawData.storage },
troubleshooting: { ...DEFAULT_SETTINGS.troubleshooting, ...rawData.troubleshooting },
tts: { ...DEFAULT_SETTINGS.tts, ...rawData.tts },
wordHighlighting: { ...DEFAULT_SETTINGS.wordHighlighting, ...rawData.wordHighlighting }
};
return _SettingsManager.validateSettings(settings);
}
static validateSettings(settings) {
const validated = { ...settings };
const defaults = DEFAULT_SETTINGS;
if (validated.tts.speed < 0.5 || validated.tts.speed > 2) {
validated.tts.speed = defaults.tts.speed;
}
if (validated.tts.pitch < -50 || validated.tts.pitch > 50) {
validated.tts.pitch = defaults.tts.pitch;
}
if (validated.troubleshooting.targetBufferAheadSeconds < 30 || validated.troubleshooting.targetBufferAheadSeconds > 180) {
validated.troubleshooting.targetBufferAheadSeconds = defaults.troubleshooting.targetBufferAheadSeconds;
}
if (typeof validated.reading.persistRewind !== "boolean") {
validated.reading.persistRewind = defaults.reading.persistRewind;
}
if (!validated.tts.voiceLocal || typeof validated.tts.voiceLocal !== "string") {
validated.tts.voiceLocal = defaults.tts.voiceLocal;
}
if (!validated.tts.voiceOnline || typeof validated.tts.voiceOnline !== "string") {
validated.tts.voiceOnline = defaults.tts.voiceOnline;
}
if (!validated.filters.ignorePhraseLine || typeof validated.filters.ignorePhraseLine !== "string") {
validated.filters.ignorePhraseLine = defaults.filters.ignorePhraseLine;
}
if (!validated.readingCompletionBehavior.stopReadingPhrase || typeof validated.readingCompletionBehavior.stopReadingPhrase !== "string") {
validated.readingCompletionBehavior.stopReadingPhrase = defaults.readingCompletionBehavior.stopReadingPhrase;
}
return validated;
}
async cleanup() {
}
getStatistics() {
return {
generatedAudioFileCount: this.settings.stats.generatedAudioFileCount,
readNoteCount: this.settings.stats.readNoteCount,
readTotalSeconds: this.settings.stats.readTotalSeconds,
restartFromBeginningCount: this.settings.stats.restartFromBeginningCount,
selectCloseCount: this.settings.stats.selectCloseCount,
selectPauseCount: this.settings.stats.selectPauseCount,
selectPlayCount: this.settings.stats.selectPlayCount,
selectReloadCount: this.settings.stats.selectReloadCount,
selectRewindCount: this.settings.stats.selectRewindCount,
viewSettingsCount: this.settings.stats.viewSettingsCount
};
}
hasVisibleStatistics() {
return this.statMeetsThreshold(1);
}
incrementStatistic(key, amount = 1) {
const statKey = key;
if (statKey in this.settings.stats && typeof this.settings.stats[statKey] === "number") {
this.settings.stats[statKey] = this.settings.stats[statKey] + amount;
}
}
isExperiencedUser() {
return this.statMeetsThreshold(100, false);
}
resetStatistics() {
this.settings.stats = {
generatedAudioFileCount: 0,
playSampleTextCounter: 0,
readNoteCount: 0,
readTotalSeconds: 0,
restartFromBeginningCount: 0,
selectCloseCount: 0,
selectPauseCount: 0,
selectPlayCount: 0,
selectReloadCount: 0,
selectRewindCount: 0,
viewSettingsCount: 0
};
}
updateSettings(newSettings) {
const updatedSettings = { ...this.settings, ...newSettings };
this.settings = _SettingsManager.validateSettings(updatedSettings);
}
statMeetsThreshold(threshold, inclusive = true) {
const stats = this.getStatistics();
return inclusive ? Object.values(stats).some((stat) => stat >= threshold) : Object.values(stats).some((stat) => stat > threshold);
}
};
const { Plugin, Notice } = require('obsidian');
module.exports = class NoteReader extends Plugin {
currentEditorView = null;
ribbonIconManager;
services = {
audioController: void 0,
audioFileGenerationCoordinator: void 0,
audioFileGenerator: void 0,
bufferManager: void 0,
commandService: void 0,
eventBus: void 0,
fileChangeMonitor: void 0,
highlightService: void 0,
interactionController: void 0,
mediaKeyManager: void 0,
mediaSourceManager: void 0,
mobileHelper: void 0,
offlineNotificationService: void 0,
progressTracker: void 0,
readerCoordinator: void 0,
readerUIView: void 0,
readingPositionService: void 0,
scrollManager: void 0,
serviceFactory: void 0,
settingsManager: void 0,
statisticsTracker: void 0,
textProcessor: void 0,
ttsServiceManager: void 0
};
settings;
logger;
loggerInstance;
constructor(app, manifest) {
super(app, manifest);
}
async onload() {
try {
const data = await this.loadData();
this.settings = SettingsManager.loadSettings(data);
this.addCommand({
callback: () => {
window.console.group("=== Current Settings ===");
const settings = this.settings;
window.console.log("tts:", JSON.stringify(settings.tts, null, 2));
window.console.log("filters:", JSON.stringify(settings.filters, null, 2));
window.console.log("storage:", JSON.stringify(settings.storage, null, 2));
window.console.log("wordHighlighting:", JSON.stringify(settings.wordHighlighting, null, 2));
window.console.log("reading:", JSON.stringify(settings.reading, null, 2));
window.console.log("readingCompletionBehavior:", JSON.stringify(settings.readingCompletionBehavior, null, 2));
window.console.log("troubleshooting:", JSON.stringify(settings.troubleshooting, null, 2));
window.console.log("stats:", JSON.stringify(settings.stats, null, 2));
window.console.log("onboarding:", JSON.stringify(settings.onboarding, null, 2));
window.console.log("showRibbonIcon:", settings.showRibbonIcon);
window.console.log("liteMode:", settings.liteMode);
window.console.groupEnd();
},
id: "log-debugging-messages",
name: "Log messages to console (debug)"
});
} catch (error) {
this.logger.handleError("Failed to load plugin", error, { component: "MainPlugin", operation: "onload" }, true);
}
}
onunload() {
try {
} catch (error) {
this.logger.handleError(
"Plugin cleanup failed",
error,
{ component: "MainPlugin", operation: "onunload" },
false
);
}
}
removeRibbonIcon(ribbonIcon) {
ribbonIcon.remove();
}
async saveSettings() {
}
};