mirror of
https://github.com/ethanolivertroy/obsidian-markitdown.git
synced 2026-07-22 05:41:54 +00:00
Merge branch 'worktree-agent-a5fb028c'
# Conflicts: # src/modals/FolderConvertModal.ts # src/types/settings.ts
This commit is contained in:
commit
678b6195be
6 changed files with 72 additions and 8 deletions
8
main.ts
8
main.ts
|
|
@ -14,6 +14,7 @@ import { checkDependencies, installPackage } from './src/utils/python';
|
|||
import {
|
||||
getVaultBasePath,
|
||||
resolveOutputFolder,
|
||||
resolveFilenameTemplate,
|
||||
resolveImageDir,
|
||||
toVaultRelative,
|
||||
} from './src/utils/paths';
|
||||
|
|
@ -147,8 +148,11 @@ export default class MarkitdownPlugin extends Plugin {
|
|||
|
||||
const inputPath = path.join(vaultPath, file.path);
|
||||
const outputFolder = resolveOutputFolder(vaultPath, this.settings.outputPath);
|
||||
const baseName = file.basename;
|
||||
const outputPath = path.join(outputFolder, `${baseName}.md`);
|
||||
const resolvedName = resolveFilenameTemplate(
|
||||
this.settings.outputFilenameTemplate || '{filename}',
|
||||
inputPath
|
||||
);
|
||||
const outputPath = path.join(outputFolder, `${resolvedName}.md`);
|
||||
const options = this.buildConversionOptions(outputPath);
|
||||
|
||||
new Notice('Converting file...');
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import * as path from 'path';
|
|||
import * as fs from 'fs';
|
||||
import type MarkitdownPlugin from '../../main';
|
||||
import { FILE_INPUT_ACCEPT } from '../utils/fileTypes';
|
||||
import { getVaultBasePath, resolveOutputFolder, toVaultRelative } from '../utils/paths';
|
||||
import { getVaultBasePath, resolveOutputFolder, resolveFilenameTemplate, toVaultRelative } from '../utils/paths';
|
||||
|
||||
export class FileConvertModal extends Modal {
|
||||
private plugin: MarkitdownPlugin;
|
||||
|
|
@ -51,8 +51,11 @@ export class FileConvertModal extends Modal {
|
|||
}
|
||||
|
||||
const outputFolder = resolveOutputFolder(vaultPath, this.plugin.settings.outputPath);
|
||||
const baseName = path.basename(file.name, path.extname(file.name));
|
||||
const outputPath = path.join(outputFolder, `${baseName}.md`);
|
||||
const resolvedName = resolveFilenameTemplate(
|
||||
this.plugin.settings.outputFilenameTemplate || '{filename}',
|
||||
file.name
|
||||
);
|
||||
const outputPath = path.join(outputFolder, `${resolvedName}.md`);
|
||||
|
||||
// Write the DOM File to a temp file on disk
|
||||
const safeName = file.name.replace(/[^a-zA-Z0-9._-]/g, '_');
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import * as path from 'path';
|
|||
import * as fs from 'fs';
|
||||
import type MarkitdownPlugin from '../../main';
|
||||
import { EXTENSION_GROUPS } from '../utils/fileTypes';
|
||||
import { getVaultBasePath, resolveOutputFolder } from '../utils/paths';
|
||||
import { getVaultBasePath, resolveOutputFolder, resolveFilenameTemplate } from '../utils/paths';
|
||||
import { BatchProgressModal } from './BatchProgressModal';
|
||||
|
||||
/**
|
||||
|
|
@ -176,7 +176,10 @@ export class FolderConvertModal extends Modal {
|
|||
progressModal?.updateProgress(i, entry.name, success, failed);
|
||||
|
||||
// Determine the output path, preserving subfolder structure
|
||||
const baseName = path.basename(entry.name, path.extname(entry.name));
|
||||
const resolvedName = resolveFilenameTemplate(
|
||||
this.plugin.settings.outputFilenameTemplate || '{filename}',
|
||||
entry.name
|
||||
);
|
||||
const relativeDir = path.dirname(entry.relativePath);
|
||||
const entryOutputFolder = relativeDir && relativeDir !== '.'
|
||||
? path.join(outputFolder, relativeDir)
|
||||
|
|
@ -185,7 +188,7 @@ export class FolderConvertModal extends Modal {
|
|||
// Ensure the output subdirectory exists
|
||||
await fs.promises.mkdir(entryOutputFolder, { recursive: true });
|
||||
|
||||
const outputPath = path.join(entryOutputFolder, `${baseName}.md`);
|
||||
const outputPath = path.join(entryOutputFolder, `${resolvedName}.md`);
|
||||
const safeName = entry.name.replace(/[^a-zA-Z0-9._-]/g, '_');
|
||||
const tempFilePath = path.join(entryOutputFolder, `tmp_${Date.now()}_${i}_${safeName}`);
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,21 @@ export class SettingsTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Output filename template')
|
||||
.setDesc(
|
||||
'Template for converted filenames. Variables: {filename} (original name), ' +
|
||||
'{ext} (original extension), {date} (YYYY-MM-DD), {datetime} (YYYY-MM-DD_HHmmss). ' +
|
||||
'The .md extension is always appended automatically.'
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('{filename}')
|
||||
.setValue(this.plugin.settings.outputFilenameTemplate)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.outputFilenameTemplate = value || '{filename}';
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Extract images')
|
||||
.setDesc('Extract embedded images from PDFs and save as separate files')
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export interface MarkitdownSettings {
|
|||
enableBatchProgress: boolean;
|
||||
enableContextMenu: boolean;
|
||||
enableRecursiveConversion: boolean;
|
||||
outputFilenameTemplate: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: MarkitdownSettings = {
|
||||
|
|
@ -27,6 +28,7 @@ export const DEFAULT_SETTINGS: MarkitdownSettings = {
|
|||
enableBatchProgress: true,
|
||||
enableContextMenu: true,
|
||||
enableRecursiveConversion: false,
|
||||
outputFilenameTemplate: '{filename}',
|
||||
};
|
||||
|
||||
export interface ConversionOptions {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,43 @@ export function resolveOutputFolder(vaultPath: string, outputSetting: string): s
|
|||
return outputFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an output filename template using variables from the input path.
|
||||
* Supported variables:
|
||||
* {filename} — original file name without extension
|
||||
* {ext} — original file extension (without dot)
|
||||
* {date} — conversion date as YYYY-MM-DD
|
||||
* {datetime} — conversion datetime as YYYY-MM-DD_HHmmss
|
||||
*
|
||||
* Returns the resolved name without .md extension (caller appends it).
|
||||
* Characters invalid in filenames are stripped from the result.
|
||||
*/
|
||||
export function resolveFilenameTemplate(template: string, inputPath: string): string {
|
||||
const baseName = path.basename(inputPath, path.extname(inputPath));
|
||||
const ext = path.extname(inputPath).replace(/^\./, '');
|
||||
|
||||
const now = new Date();
|
||||
const pad = (n: number) => String(n).padStart(2, '0');
|
||||
const date = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
|
||||
const datetime = `${date}_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
||||
|
||||
let resolved = template
|
||||
.replace(/\{filename\}/g, baseName)
|
||||
.replace(/\{ext\}/g, ext)
|
||||
.replace(/\{date\}/g, date)
|
||||
.replace(/\{datetime\}/g, datetime);
|
||||
|
||||
// Remove characters invalid in filenames
|
||||
resolved = resolved.replace(/[/\\:*?"<>|]/g, '');
|
||||
|
||||
// Fall back to the original filename if the result is empty after sanitisation
|
||||
if (!resolved.trim()) {
|
||||
resolved = baseName;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the image extraction directory for a given output markdown file.
|
||||
* Applies the template (e.g., "{filename}-images") to generate the folder name.
|
||||
|
|
|
|||
Loading…
Reference in a new issue