mirror of
https://github.com/ethanolivertroy/obsidian-markitdown.git
synced 2026-07-22 05:41:54 +00:00
Add custom output filename template (ENG-649)
This commit is contained in:
parent
a93ed8341d
commit
cac2a1bbd8
6 changed files with 72 additions and 8 deletions
8
main.ts
8
main.ts
|
|
@ -13,6 +13,7 @@ import { checkDependencies, installPackage } from './src/utils/python';
|
|||
import {
|
||||
getVaultBasePath,
|
||||
resolveOutputFolder,
|
||||
resolveFilenameTemplate,
|
||||
resolveImageDir,
|
||||
toVaultRelative,
|
||||
} from './src/utils/paths';
|
||||
|
|
@ -123,8 +124,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';
|
||||
|
||||
export class FolderConvertModal extends Modal {
|
||||
|
|
@ -119,8 +119,11 @@ export class FolderConvertModal extends Modal {
|
|||
const file = files[i];
|
||||
progressModal?.updateProgress(i, file.name, success, failed);
|
||||
|
||||
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`);
|
||||
const safeName = file.name.replace(/[^a-zA-Z0-9._-]/g, '_');
|
||||
const tempFilePath = path.join(outputFolder, `tmp_${Date.now()}_${i}_${safeName}`);
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,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')
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export interface MarkitdownSettings {
|
|||
imageSubfolderTemplate: string;
|
||||
enableBatchProgress: boolean;
|
||||
enableContextMenu: boolean;
|
||||
outputFilenameTemplate: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: MarkitdownSettings = {
|
||||
|
|
@ -25,6 +26,7 @@ export const DEFAULT_SETTINGS: MarkitdownSettings = {
|
|||
imageSubfolderTemplate: '{filename}-images',
|
||||
enableBatchProgress: true,
|
||||
enableContextMenu: true,
|
||||
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