ethanolivertroy_obsidian-ma.../main.js

234 lines
48 KiB
JavaScript
Raw Permalink Normal View History

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
"use strict";var Ct=Object.create;var L=Object.defineProperty;var _t=Object.getOwnPropertyDescriptor;var Tt=Object.getOwnPropertyNames;var Dt=Object.getPrototypeOf,St=Object.prototype.hasOwnProperty;var Ft=(p,n)=>{for(var t in n)L(p,t,{get:n[t],enumerable:!0})},pt=(p,n,t,e)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of Tt(n))!St.call(p,s)&&s!==t&&L(p,s,{get:()=>n[s],enumerable:!(e=_t(n,s))||e.enumerable});return p};var x=(p,n,t)=>(t=p!=null?Ct(Dt(p)):{},pt(n||!p||!p.__esModule?L(t,"default",{value:p,enumerable:!0}):t,p)),Mt=p=>pt(L({},"__esModule",{value:!0}),p);var Ht={};Ft(Ht,{default:()=>K});module.exports=Mt(Ht);var y=require("obsidian"),b=x(require("path")),at=x(require("fs"));var X={pythonPath:"python",enablePlugins:!1,pluginArgs:[],docintelEndpoint:"",outputPath:"",imageExtractionEnabled:!1,imageSubfolderTemplate:"{filename}-images",enableBatchProgress:!0,enableContextMenu:!0,enableRecursiveConversion:!1,outputFilenameTemplate:"{filename}",enableDragDrop:!0,enableAutoFrontmatter:!1,autoTags:"",conversionHistory:[]};var M=x(require("fs"));var Q=require("child_process"),k=x(require("path")),Z=".venv",ct=["3.14","3.13","3.12","3.11","3.10","3.9"];function ut(p){let n=process.env.HOME||process.env.USERPROFILE||"",t=process.platform==="win32",e=t?";":":",s=[];t||s.push("/opt/homebrew/bin","/usr/local/bin"),n&&(s.push(k.join(n,".local","bin")),t||s.push(k.join(n,".pyenv","shims")));let a=process.env.PATH||"",o=[...s,a].filter(Boolean),l=new Set,r=o.filter(i=>l.has(i)?!1:(l.add(i),!0));return{...process.env,PYTHONUTF8:"1",PATH:r.join(e),...p}}function It(p){return process.platform==="win32"?k.join(p,Z,"Scripts","python.exe"):k.join(p,Z,"bin","python")}function $t(p,n){let t=p.trim(),e=[];t&&e.push(t),e.push(It(n));let s=process.env.HOME||process.env.USERPROFILE||"",a=process.platform==="win32",o=[];if(process.env.PIPX_HOME&&o.push(process.env.PIPX_HOME),s)if(o.push(k.join(s,".local","pipx")),a){let r=process.env.LOCALAPPDATA||k.join(s,"AppData","Local");o.push(k.join(r,"pipx"))}else process.platform==="darwin"?o.push(k.join(s,"Library","Application Support","pipx")):o.push(k.join(s,".local","share","pipx"));for(let r of o)a?e.push(k.join(r,"venvs","markitdown","Scripts","python.exe")):e.push(k.join(r,"venvs","markitdown","bin","python"));if(a){t==="python"?e.push("python3"):t==="python3"?e.push("python"):e.push("python","python3");let r=process.env.LOCALAPPDATA||"";if(r){for(let i of["314","313","312","311","310","39"])e.push(`${r}\\Programs\\Python\\Python${i}\\python.exe`);e.push(`${r}\\Microsoft\\WindowsApps\\python3.exe`)}}else{t==="python"?e.push("python3"):t==="python3"?e.push("python"):e.push("python3","python"),e.push("/opt/homebrew/bin/python3"),e.push("/usr/local/bin/python3");for(let r of ct)e.push(`/opt/homebrew/bin/python${r}`),e.push(`/usr/local/bin/python${r}`),e.push(`/opt/homebrew/opt/python@${r}/bin/python3`),e.push(`/usr/local/opt/python@${r}/bin/python3`);for(let r of ct)e.push(`/Library/Frameworks/Python.framework/Versions/${r}/bin/python3`);e.push("/usr/bin/python3")}let l=new Set;return e.filter(r=>!r||l.has(r)?!1:(l.add(r),!0))}function O(p,n,t,e){return new Promise((s,a)=>{let o=(0,Q.spawn)(p,[n,...t],{shell:!1,env:ut(e),stdio:["ignore","pipe","pipe"]}),l="",r="";o.stdout.on("data",i=>{l+=i.toString()}),o.stderr.on("data",i=>{r+=i.toString()}),o.on("error",i=>{a(i)}),o.on("close",i=>{s({stdout:l.trim(),stderr:r.trim(),exitCode:i??1})})})}function A(p,n){return k.join(n,"python",p)}async function tt(p,n){let t={pythonInstalled:!1,pythonVersion:null,markitdownInstalled:!1,markitdownVersion:null},e=[],s=p.trim();if(!s)return e.push({path:p||"(empty)",error:"Path is empty or whitespace-only"}),{status:t,resolvedPythonPath:p,triedPaths:e};let a=A("check_install.py",n),o=$t(s,n),l=null;for(let r of o)try{let i=await O(r,a,["--check","all"]);if(i.exitCode===0&&i.stdout){let c=JSON.parse(i.stdout),u={pythonInstalled:!0,pythonVersion:c.python_version??null,markitdownInstalled:!1,markitdownVersion:null};if(c.packages?.markitdown&&(u.markitdownInstalled=c.packages.markitdown.installed,u.mar
`);i=d.pop()??"";for(let m of d)m.trim()&&(c=m.trim(),e?.(m.trim()))}),r.stderr.on("data",u=>{let d=u.toString().split(`
`);for(let m of d)m.trim()&&e?.(m.trim())}),r.on("error",u=>{a(u)}),r.on("close",u=>{let d=i.trim();if(d&&(c=d,e?.(d)),u===0)try{let m=JSON.parse(c);s(m.success===!0)}catch{s(!0)}else s(!1)})}):!1}var j=["pdf","docx","pptx","xlsx","xls","html","htm","txt","csv","json","xml","jpg","jpeg","png","gif","wav","mp3","zip","epub"],gt=j.map(p=>`.${p}`).join(","),ht=[{name:"PDF files",extensions:".pdf"},{name:"Word documents",extensions:".docx"},{name:"PowerPoint presentations",extensions:".pptx"},{name:"Excel spreadsheets",extensions:".xlsx,.xls"},{name:"Web pages",extensions:".html,.htm"},{name:"Text files",extensions:".txt"},{name:"Data files",extensions:".csv,.json,.xml"},{name:"Images",extensions:".jpg,.jpeg,.png,.gif"},{name:"Audio files",extensions:".wav,.mp3"},{name:"Archives & eBooks",extensions:".zip,.epub"}];function et(p){let n=p.toLowerCase().replace(/^\./,"");return j.includes(n)}var ft=x(require("path"));function mt(p){return/[:#\[\]{}&*!|>'"`,@%\\]/.test(p)||p.trim()!==p?`"${p.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:p}function At(p,n){let t={};if(n.enableAutoFrontmatter){let e=ft.basename(p),s=new Date,a=s.getFullYear(),o=String(s.getMonth()+1).padStart(2,"0"),l=String(s.getDate()).padStart(2,"0");t.source=e,t.converted=`${a}-${o}-${l}`,t.converter="markitdown"}if(n.autoTags.trim()){let e=n.autoTags.split(",").map(s=>s.trim()).filter(s=>s.length>0);e.length>0&&(t.tags=e)}return t}function vt(p){let n=[];for(let[t,e]of Object.entries(p))if(Array.isArray(e)){n.push(`${t}:`);for(let s of e)n.push(` - ${mt(s)}`)}else n.push(`${t}: ${mt(e)}`);return n.join(`
`)}function Nt(p){if(!p.startsWith("---"))return null;let n=p.indexOf(`
---`,3);if(n===-1)return null;let t=p.substring(4,n).trim(),e=n+4,s=p.substring(e);return{yaml:t,body:s}}function Lt(p,n){let t=new Set;for(let a of p.split(`
`)){let o=a.match(/^(\w[\w-]*)\s*:/);o&&t.add(o[1])}let e={};for(let[a,o]of Object.entries(n))t.has(a)||(e[a]=o);if(Object.keys(e).length===0)return p;let s=vt(e);return p+`
`+s}function wt(p,n,t){let e=At(n,t);if(Object.keys(e).length===0)return p;let s=Nt(p);return s?`---
${Lt(s.yaml,e)}
---${s.body}`:`---
${vt(e)}
---
${p}`}var I=class{constructor(n,t){this.pythonPath=n;this.pluginDir=t}getSupportedExtensions(){return j.map(n=>`.${n}`)}canConvert(n){let t=n.startsWith(".")?n.toLowerCase():`.${n.toLowerCase()}`;return this.getSupportedExtensions().includes(t)}async convertUrl(n,t,e){let s=Date.now(),a=A("markitdown_wrapper.py",this.pluginDir),o=["--url",n,"--output",t];e?.enablePlugins&&o.push("--enable-plugins"),e?.pluginArgs&&Object.keys(e.pluginArgs).length>0&&o.push("--plugin-args",JSON.stringify(e.pluginArgs)),e?.docintelEndpoint&&o.push("--docintel-endpoint",e.docintelEndpoint);try{let l=await O(this.pythonPath,a,o);if(l.exitCode!==0){let r="Unknown error";try{r=JSON.parse(l.stderr).error||"Unknown error"}catch{r=l.stderr||"Unknown error"}return r=r.replace(/(?:\/[\w.-]+)+\//g,"\u2026/"),{success:!1,error:`Conversion failed: ${r}`,processingTime:Date.now()-s}}return M.existsSync(t)?{success:!0,outputPath:t,processingTime:Date.now()-s}:{success:!1,error:"Output file was not created",processingTime:Date.now()-s}}catch(l){return{success:!1,error:`Conversion error: ${(l instanceof Error?l.message:String(l)).replace(/(?:\/[\w.-]+)+\//g,"\u2026/")}`,processingTime:Date.now()-s}}}async convert(n,t,e){let s=Date.now(),a=A("markitdown_wrapper.py",this.pluginDir),o=["--input",n,"--output",t];e?.enablePlugins&&o.push("--enable-plugins"),e?.pluginArgs&&Object.keys(e.pluginArgs).length>0&&o.push("--plugin-args",JSON.stringify(e.pluginArgs)),e?.docintelEndpoint&&o.push("--docintel-endpoint",e.docintelEndpoint),e?.extractImages&&e?.imageDir&&o.push("--extract-images","--image-dir",e.imageDir);try{let l=await O(this.pythonPath,a,o);if(l.exitCode!==0){let i="Unknown error";try{i=JSON.parse(l.stderr).error||"Unknown error"}catch{i=l.stderr||"Unknown error"}return i=i.replace(/(?:\/[\w.-]+)+\//g,"\u2026/"),{success:!1,error:`Conversion failed: ${i}`,processingTime:Date.now()-s}}if(!M.existsSync(t))return{success:!1,error:"Output file was not created",processingTime:Date.now()-s};if(e?.postProcess)try{let i=M.readFileSync(t,"utf-8"),c=wt(i,e.postProcess.inputPath,e.postProcess.settings);c!==i&&M.writeFileSync(t,c,"utf-8")}catch(i){console.warn("markitdown: post-conversion hook error:",i)}let r=0;try{r=JSON.parse(l.stdout).images_extracted??0}catch{}return{success:!0,outputPath:t,processingTime:Date.now()-s,imagesExtracted:r}}catch(l){return{success:!1,error:`Conversion error: ${(l instanceof Error?l.message:String(l)).replace(/(?:\/[\w.-]+)+\//g,"\u2026/")}`,processingTime:Date.now()-s}}}};var yt=require("obsidian"),h=x(require("path")),R=x(require("fs"));function P(p){return p.vault.adapter instanceof yt.FileSystemAdapter?p.vault.adapter.getBasePath():null}function E(p,n){let t;n?t=h.resolve(p,n):t=h.join(p,"markitdown-output");let e=h.resolve(p);return!t.startsWith(e+h.sep)&&t!==e&&(t=h.join(p,"markitdown-output")),R.existsSync(t)||R.mkdirSync(t,{recursive:!0}),t}function $(p,n){let t=h.basename(n,h.extname(n)),e=h.extname(n).replace(/^\./,""),s=new Date,a=i=>String(i).padStart(2,"0"),o=`${s.getFullYear()}-${a(s.getMonth()+1)}-${a(s.getDate())}`,l=`${o}_${a(s.getHours())}${a(s.getMinutes())}${a(s.getSeconds())}`,r=p.replace(/\{filename\}/g,t).replace(/\{ext\}/g,e).replace(/\{date\}/g,o).replace(/\{datetime\}/g,l);return r=r.replace(/[/\\:*?"<>|]/g,""),r.trim()||(r=t),r}function xt(p,n){let t=h.dirname(p),e=h.basename(p,".md"),a=n.replace(/[/\\]/g,"-").replace("{filename}",e);return h.join(t,a)}function nt(p,n){return h.relative(n,p).replace(/\\/g,"/")}var Ot=100;function st(p,n){return p.conversionHistory=[n,...p.conversionHistory].slice(0,Ot),p.conversionHistory}var V=x(require("fs")),rt=x(require("path")),jt=`#!/usr/bin/env python3
"""Check Python environment and installed packages."""
import argparse
import json
import sys
ALLOWED_PACKAGES = {"markitdown"}
def check_package(name):
if name not in ALLOWED_PACKAGES:
return {"installed": False, "version": None}
if name == "markitdown":
try:
from markitdown import MarkItDown
except (ImportError, AttributeError, TypeError):
return {"installed": False, "version": None}
try:
from importlib.metadata import version, PackageNotFoundError
try:
ver = version(name)
return {"installed": True, "version": ver}
except PackageNotFoundError:
return {"installed": False, "version": None}
except ImportError:
try:
import pkg_resources
ver = pkg_resources.get_distribution(name).version
return {"installed": True, "version": ver}
except Exception:
return {"installed": False, "version": None}
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--check", required=True)
args = parser.parse_args()
packages = ["markitdown"] if args.check == "all" else [args.check]
result = {"python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", "packages": {}}
for pkg in packages:
result["packages"][pkg] = check_package(pkg)
print(json.dumps(result))
if __name__ == "__main__":
main()
`,Rt=`#!/usr/bin/env python3
"""Install a Python package into a plugin-managed virtual environment."""
import argparse
import json
import os
import shutil
import subprocess
import sys
def venv_python(venv_dir):
if sys.platform == "win32":
return os.path.join(venv_dir, "Scripts", "python.exe")
return os.path.join(venv_dir, "bin", "python")
def run_pip(python, package):
process = subprocess.Popen(
[python, "-m", "pip", "install", package],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1)
if process.stdout is not None:
for line in process.stdout:
print(line, end="", flush=True)
process.wait()
return process.returncode or 0
def ensure_venv(venv_dir, bootstrap_python):
py = venv_python(venv_dir)
if os.path.isfile(py):
return py
print(f"Creating virtual environment at {venv_dir}...", flush=True)
result = subprocess.run(
[bootstrap_python, "-m", "venv", venv_dir],
capture_output=True, text=True)
if result.returncode != 0 or not os.path.isfile(py):
shutil.rmtree(venv_dir, ignore_errors=True)
detail = (result.stderr or result.stdout or "").strip()
raise RuntimeError(
f"Failed to create virtual environment at {venv_dir}: {detail or f'exit {result.returncode}'}")
return py
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--package", required=True)
parser.add_argument("--venv-dir", required=True)
args = parser.parse_args()
try:
py = ensure_venv(args.venv_dir, sys.executable)
print(f"Installing {args.package} into {py}...", flush=True)
code = run_pip(py, args.package)
if code == 0:
print(json.dumps({"success": True, "python_path": py}))
else:
print(json.dumps({"success": False, "error": f"pip exited with code {code}"}))
sys.exit(1)
except Exception as e:
print(json.dumps({"success": False, "error": str(e)}))
sys.exit(1)
if __name__ == "__main__":
main()
`,Vt=`#!/usr/bin/env python3
"""Convert files to Markdown using Microsoft's Markitdown."""
import argparse
import base64
import json
import os
import re
import sys
import time
def extract_images_from_markdown(markdown_text, image_dir):
os.makedirs(image_dir, exist_ok=True)
count = 0
image_dir_name = os.path.basename(image_dir)
pattern = r'(!\\[[^\\]]*\\])\\(data:image/([^;]+);base64,([A-Za-z0-9+/=\\s]+)\\)'
def replace_data_uri(match):
nonlocal count
next_index = count + 1
alt_text = match.group(1)
img_format = match.group(2)
b64_data = match.group(3).replace("\\n", "").replace("\\r", "").replace(" ", "")
ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif", "bmp", "tiff", "tif", "webp", "svg", "ico"}
ext = img_format.lower()
if ext == "jpeg": ext = "jpg"
elif ext == "svg+xml": ext = "svg"
ext = re.sub(r'[^a-z0-9]', '', ext)
if ext not in ALLOWED_EXTENSIONS: ext = "png"
filename = f"image_{next_index:03d}.{ext}"
filepath = os.path.join(image_dir, filename)
try:
image_bytes = base64.b64decode(b64_data)
with open(filepath, "wb") as f:
f.write(image_bytes)
except Exception as e:
print(json.dumps({"warning": f"Failed to decode image {next_index}: {e}"}), file=sys.stderr)
return match.group(0)
count = next_index
return f"{alt_text}(./{image_dir_name}/{filename})"
updated_markdown = re.sub(pattern, replace_data_uri, markdown_text)
return updated_markdown, count
def main():
parser = argparse.ArgumentParser(description="Convert files to Markdown using Markitdown")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--input", help="Input file path")
group.add_argument("--url", help="URL to convert")
parser.add_argument("--output", required=True, help="Output markdown file path")
parser.add_argument("--enable-plugins", action="store_true")
parser.add_argument("--plugin-args", default="{}")
parser.add_argument("--docintel-endpoint")
parser.add_argument("--extract-images", action="store_true")
parser.add_argument("--image-dir")
args = parser.parse_args()
if args.extract_images and not args.image_dir:
parser.error("--image-dir is required when --extract-images is specified")
start_time = time.time()
try:
source = args.url if args.url else args.input
if args.input:
if not os.path.isfile(args.input):
print(json.dumps({"error": f"Input file does not exist: {os.path.basename(args.input)}", "type": "FileError"}), file=sys.stderr)
sys.exit(1)
if not os.access(args.input, os.R_OK):
print(json.dumps({"error": f"Input file is not readable: {os.path.basename(args.input)}", "type": "FileError"}), file=sys.stderr)
sys.exit(1)
if args.url:
if not args.url.startswith(("http://", "https://")):
print(json.dumps({"error": "URL must start with http:// or https://", "type": "ValueError"}), file=sys.stderr)
sys.exit(1)
if args.docintel_endpoint:
os.environ["AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT"] = args.docintel_endpoint
try:
from markitdown import MarkItDown
except ImportError:
print(json.dumps({"error": "markitdown package is not installed. Run: pip install 'markitdown[all]'", "type": "ImportError"}), file=sys.stderr)
sys.exit(1)
plugin_kwargs = {}
if args.plugin_args and args.plugin_args != "{}":
try:
plugin_kwargs = json.loads(args.plugin_args)
except json.JSONDecodeError as e:
print(json.dumps({"error": f"Invalid plugin-args JSON: {e}", "type": "ValueError"}), file=sys.stderr)
sys.exit(1)
if not isinstance(plugin_kwargs, dict):
print(json.dumps({"error": "plugin-args must be a JSON object", "type": "ValueError"}), file=sys.stderr)
sys.exit(1)
converter_kwargs = {}
if args.enable_plugins:
converter_kwargs["enable_plugins"] = True
converter = MarkItDown(**converter_kwargs)
result = converter.convert(source, **plugin_kwargs)
markdown_text = result.text_content
if not markdown_text:
print(json.dumps({"error": "Conversion produced empty output", "type": "ConversionError"}), file=sys.stderr)
sys.exit(1)
images_extracted = 0
if args.extract_images and args.image_dir:
markdown_text, images_extracted = extract_images_from_markdown(markdown_text, args.image_dir)
output_dir = os.path.dirname(os.path.abspath(args.output))
if output_dir:
os.makedirs(output_dir, exist_ok=True)
with open(args.output, "w", encoding="utf-8") as f:
f.write(markdown_text)
elapsed_ms = int((time.time() - start_time) * 1000)
print(json.dumps({"success": True, "images_extracted": images_extracted, "processing_time_ms": elapsed_ms}))
except Exception as e:
print(json.dumps({"error": str(e), "type": type(e).__name__}), file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
`,Bt={"check_install.py":jt,"install_package.py":Rt,"markitdown_wrapper.py":Vt};async function kt(p){let n=rt.join(p,"python");try{await V.promises.mkdir(n,{recursive:!0})}catch{}for(let[t,e]of Object.entries(Bt)){let s=rt.join(n,t);try{if(await V.promises.readFile(s,"utf-8")===e)continue}catch{}await V.promises.writeFile(s,e,"utf-8")}}var g=require("obsidian");var B=class{constructor(n,t,e){this.containerEl=n;this.entries=t;this.onChange=e}render(){this.containerEl.empty();for(let t=0;t<this.entries.length;t++){let e=this.containerEl.createDiv("markitdown-plugin-arg-row"),s=e.createEl("input",{attr:{type:"text",placeholder:"Argument name"},cls:"markitdown-plugin-arg-key"});s.value=this.entries[t].key,s.addEventListener("input",()=>{this.entries[t].key=s.value,this.onChange(this.entries)});let a=e.createEl("input",{attr:{type:"text",placeholder:"Value"},cls:"markitdown-plugin-arg-value"});a.value=this.entries[t].value,a.addEventListener("input",()=>{this.entries[t].value=a.value,this.onChange(this.entries)}),e.createEl("button",{text:"\xD7",cls:"markitdown-plugin-arg-delete",attr:{"aria-label":"Remove argument"}}).addEventListener("click",()=>{this.entries.splice(t,1),this.onChange(this.entries),this.render()})}this.containerEl.createEl("button",{text:"+ Add argument",cls:"markitdown-plugin-arg-add"}).addEventListener("click",()=>{this.entries.push({key:"",value:""}),this.onChange(this.entries),this.render()})}};var H=class extends g.PluginSettingTab{constructor(t,e){super(t,e);this.pythonPathDebounceTimer=null;this.plugin=e}hide(){this.pythonPathDebounceTimer&&(clearTimeout(this.pythonPathDebounceTimer),this.pythonPathDebounceTimer=null,this.plugin.refreshDependencies().catch(console.error))}cancelPythonPathDebounce(){this.pythonPathDebounceTimer&&(clearTimeout(this.pythonPathDebounceTimer),this.pythonPathDebounceTimer=null)}display(){this.cancelPythonPathDebounce();let{containerEl:t}=this;t.empty(),new g.Setting(t).setName("Python").setHeading(),new g.Setting(t).setName("Python path").setDesc("Path to Python executable (e.g., python, python3, or a full path like C:\\Python311\\python.exe)").addText(r=>r.setPlaceholder("python").setValue(this.plugin.settings.pythonPath).onChange(async i=>{this.plugin.settings.pythonPath=i,await this.plugin.saveSettings(),this.pythonPathDebounceTimer&&clearTimeout(this.pythonPathDebounceTimer),this.pythonPathDebounceTimer=setTimeout(async()=>{this.pythonPathDebounceTimer=null,await this.plugin.refreshDependencies(),this.containerEl.isConnected&&this.display()},1500)}));let e=this.plugin.settings.pythonPath||"python",s=this.plugin.resolvedPythonPath;if(s&&s!==e&&t.createDiv("markitdown-resolved-path-hint").setText(`Resolved: ${s}`),new g.Setting(t).setName("Conversion").setHeading(),new g.Setting(t).setName("Output folder").setDesc('Folder for converted files (relative to vault root). Leave empty for "markitdown-output".').addText(r=>r.setPlaceholder("markitdown-output").setValue(this.plugin.settings.outputPath).onChange(async i=>{this.plugin.settings.outputPath=i,await this.plugin.saveSettings()})),new g.Setting(t).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(r=>r.setPlaceholder("{filename}").setValue(this.plugin.settings.outputFilenameTemplate).onChange(async i=>{this.plugin.settings.outputFilenameTemplate=i||"{filename}",await this.plugin.saveSettings()})),new g.Setting(t).setName("Extract images").setDesc("Extract embedded images from PDFs and save as separate files").addToggle(r=>r.setValue(this.plugin.settings.imageExtractionEnabled).onChange(async i=>{this.plugin.settings.imageExtractionEnabled=i,await this.plugin.saveSettings(),this.display()})),this.plugin.settings.imageExtractionEnabled&&new g.Setting(t).setName("Image subfolder").setDesc("Subfolder name template for extracted images. Use {filename} as placeholder.").addText(r=>r.setPlaceholder("{filename}-images").
`+l.join(`
`)),new C.Notice(r)}}onClose(){this.contentEl.empty()}};var _=require("obsidian"),Pt=x(require("path"));var q=class extends _.Modal{constructor(n,t){super(n),this.plugin=t}onOpen(){let{contentEl:n}=this;n.addClass("markitdown-modal"),n.createEl("h2",{text:"Convert URL to Markdown"}),n.createEl("p",{text:"Enter a URL to convert (e.g. YouTube):"});let e=n.createDiv("markitdown-url-input-container").createEl("input",{attr:{type:"url",placeholder:"https://www.youtube.com/watch?v=..."}});e.style.width="100%";let a=n.createDiv("markitdown-button-container").createEl("button",{text:"Convert",cls:"mod-cta"});a.addEventListener("click",async()=>{let o=e.value.trim();if(!o){new _.Notice("Please enter a URL");return}if(!o.startsWith("http://")&&!o.startsWith("https://")){new _.Notice("URL must start with http:// or https://");return}a.disabled=!0,a.setText("Converting...");try{let l=P(this.app);if(!l){new _.Notice("Could not determine vault path. This plugin requires a local vault."),a.disabled=!1,a.setText("Convert");return}let r=E(l,this.plugin.settings.outputPath),i=this.deriveFilename(o),c=Pt.join(r,`${i}.md`),u=this.plugin.buildConversionOptions(c),d=await this.plugin.converter.convertUrl(o,c,u);d.success?(new _.Notice("URL converted successfully"),this.close(),await this.plugin.openConvertedFile(c,l)):(new _.Notice(`Conversion failed: ${d.error}`),a.disabled=!1,a.setText("Convert"))}catch(l){let r=l instanceof Error?l.message:String(l);new _.Notice(`Error: ${r}`),a.disabled=!1,a.setText("Convert")}})}deriveFilename(n){try{let t=new URL(n);if(t.hostname==="www.youtube.com"||t.hostname==="youtube.com"||t.hostname==="m.youtube.com"){let s=t.searchParams.get("v");if(s)return`youtube-${s}`}if(t.hostname==="youtu.be"){let s=t.pathname.slice(1);if(s)return`youtube-${s}`}return`${t.hostname}${t.pathname}`.replace(/[^a-zA-Z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"")||"url-conversion"}catch{return`url-${Date.now()}`}}onClose(){this.contentEl.empty()}};var J=require("obsidian"),z=class extends J.Modal{constructor(n,t){super(n),this.plugin=t}onOpen(){let{contentEl:n}=this;n.addClass("markitdown-modal"),n.createEl("h2",{text:"Conversion history"});let t=this.plugin.settings.conversionHistory;if(t.length===0){n.createEl("p",{text:"No conversions have been recorded yet.",cls:"markitdown-history-empty"});return}let e=n.createDiv("markitdown-history-list");for(let o of t)this.renderEntry(e,o);n.createDiv("markitdown-button-container").createEl("button",{text:"Clear history",cls:"markitdown-history-clear-btn"}).addEventListener("click",async()=>{this.plugin.settings.conversionHistory=[],await this.plugin.saveSettings(),new J.Notice("Conversion history cleared"),this.close()})}renderEntry(n,t){let e=n.createDiv("markitdown-history-entry"),s=e.createDiv("markitdown-history-entry-header"),a=new Date(t.timestamp);s.createSpan({text:a.toLocaleString(),cls:"markitdown-history-timestamp"});let o=t.success?"markitdown-history-badge-success":"markitdown-history-badge-fail";s.createSpan({text:t.success?"Success":"Failed",cls:`markitdown-history-badge ${o}`});let l=t.inputFile.split("/").pop()?.split("\\").pop()??t.inputFile;e.createDiv({text:l,cls:"markitdown-history-filename"});let r=[];t.processingTimeMs!==void 0&&r.push(`${t.processingTimeMs}ms`),t.imagesExtracted!==void 0&&t.imagesExtracted>0&&r.push(`${t.imagesExtracted} image${t.imagesExtracted!==1?"s":""} extracted`),r.length>0&&e.createDiv({text:r.join(" \xB7 "),cls:"markitdown-history-details"}),!t.success&&t.error&&e.createDiv({text:t.error,cls:"markitdown-history-error"})}onClose(){this.contentEl.empty()}};var G=require("obsidian"),F=class extends G.Modal{constructor(n,t){super(n),this.plugin=t}onOpen(){let{contentEl:n}=this;if(n.addClass("markitdown-modal"),n.createEl("h2",{text:"Markitdown setup"}),!this.plugin.dependencyStatus.pythonInstalled){this.showPythonNotFound(n);return}if(this.plugin.dependencyStatus.markitdownInstalled){this.showAlreadyInstalled(n);return}this.showInstallPrompt(n)}showPythonNotFound(n){n.createEl("p",{text:"Python is not installed or not found at the c