mdengine 0.2.2__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mdengine-0.2.2 → mdengine-0.4.0}/PKG-INFO +179 -6
- {mdengine-0.2.2 → mdengine-0.4.0}/README.md +152 -3
- {mdengine-0.2.2 → mdengine-0.4.0}/pyproject.toml +44 -3
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/__init__.py +1 -1
- mdengine-0.4.0/src/md_generator/media/__init__.py +21 -0
- mdengine-0.4.0/src/md_generator/media/audio/__init__.py +18 -0
- mdengine-0.4.0/src/md_generator/media/audio/api/__init__.py +1 -0
- mdengine-0.4.0/src/md_generator/media/audio/api/main.py +175 -0
- mdengine-0.4.0/src/md_generator/media/audio/api/mcp_server.py +38 -0
- mdengine-0.4.0/src/md_generator/media/audio/api/mcp_setup.py +84 -0
- mdengine-0.4.0/src/md_generator/media/audio/api/run.py +30 -0
- mdengine-0.4.0/src/md_generator/media/audio/api/settings.py +26 -0
- mdengine-0.4.0/src/md_generator/media/audio/converter.py +178 -0
- mdengine-0.4.0/src/md_generator/media/audio/formatter.py +70 -0
- mdengine-0.4.0/src/md_generator/media/audio/service.py +52 -0
- mdengine-0.4.0/src/md_generator/media/document_converter.py +239 -0
- mdengine-0.4.0/src/md_generator/media/job_store.py +94 -0
- mdengine-0.4.0/src/md_generator/media/video/__init__.py +9 -0
- mdengine-0.4.0/src/md_generator/media/video/api/__init__.py +1 -0
- mdengine-0.4.0/src/md_generator/media/video/api/main.py +174 -0
- mdengine-0.4.0/src/md_generator/media/video/api/mcp_server.py +38 -0
- mdengine-0.4.0/src/md_generator/media/video/api/mcp_setup.py +84 -0
- mdengine-0.4.0/src/md_generator/media/video/api/run.py +30 -0
- mdengine-0.4.0/src/md_generator/media/video/api/settings.py +26 -0
- mdengine-0.4.0/src/md_generator/media/video/converter.py +111 -0
- mdengine-0.4.0/src/md_generator/media/video/formatter.py +81 -0
- mdengine-0.4.0/src/md_generator/media/video/service.py +79 -0
- mdengine-0.4.0/src/md_generator/media/whisper_language.py +78 -0
- mdengine-0.4.0/src/md_generator/media/youtube/__init__.py +34 -0
- mdengine-0.4.0/src/md_generator/media/youtube/api/__init__.py +1 -0
- mdengine-0.4.0/src/md_generator/media/youtube/api/main.py +140 -0
- mdengine-0.4.0/src/md_generator/media/youtube/api/mcp_server.py +31 -0
- mdengine-0.4.0/src/md_generator/media/youtube/api/mcp_setup.py +48 -0
- mdengine-0.4.0/src/md_generator/media/youtube/api/run.py +30 -0
- mdengine-0.4.0/src/md_generator/media/youtube/api/settings.py +24 -0
- mdengine-0.4.0/src/md_generator/media/youtube/converter.py +140 -0
- mdengine-0.4.0/src/md_generator/media/youtube/formatter.py +58 -0
- mdengine-0.4.0/src/md_generator/media/youtube/metadata.py +210 -0
- mdengine-0.4.0/src/md_generator/media/youtube/service.py +200 -0
- mdengine-0.4.0/src/md_generator/media/youtube/transcript.py +100 -0
- mdengine-0.4.0/src/md_generator/playwright/__init__.py +6 -0
- mdengine-0.4.0/src/md_generator/playwright/api/__init__.py +1 -0
- mdengine-0.4.0/src/md_generator/playwright/api/convert_runner.py +71 -0
- mdengine-0.4.0/src/md_generator/playwright/api/jobs.py +92 -0
- mdengine-0.4.0/src/md_generator/playwright/api/main.py +295 -0
- mdengine-0.4.0/src/md_generator/playwright/api/mcp_server.py +37 -0
- mdengine-0.4.0/src/md_generator/playwright/api/mcp_setup.py +58 -0
- mdengine-0.4.0/src/md_generator/playwright/api/run.py +29 -0
- mdengine-0.4.0/src/md_generator/playwright/api/settings.py +26 -0
- mdengine-0.4.0/src/md_generator/playwright/assets.py +119 -0
- mdengine-0.4.0/src/md_generator/playwright/chunker.py +53 -0
- mdengine-0.4.0/src/md_generator/playwright/cli.py +131 -0
- mdengine-0.4.0/src/md_generator/playwright/extractor.py +24 -0
- mdengine-0.4.0/src/md_generator/playwright/html_to_md.py +25 -0
- mdengine-0.4.0/src/md_generator/playwright/options.py +35 -0
- mdengine-0.4.0/src/md_generator/playwright/pipeline.py +65 -0
- mdengine-0.4.0/src/md_generator/playwright/playwright_fetcher.py +107 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/mdengine.egg-info/PKG-INFO +179 -6
- {mdengine-0.2.2 → mdengine-0.4.0}/src/mdengine.egg-info/SOURCES.txt +53 -0
- mdengine-0.4.0/src/mdengine.egg-info/entry_points.txt +21 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/mdengine.egg-info/requires.txt +28 -0
- mdengine-0.2.2/src/mdengine.egg-info/entry_points.txt +0 -9
- {mdengine-0.2.2 → mdengine-0.4.0}/LICENSE +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/setup.cfg +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/api/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/api/convert_runner.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/api/jobs.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/api/main.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/api/mcp_server.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/api/mcp_setup.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/api/query_options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/api/settings.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/convert_impl.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/converter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/archive/options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/api/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/api/main.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/api/mcp_server.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/api/query_options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/api/settings.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/api/staging.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/api/zip_bundle.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/backends/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/backends/base.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/backends/easy.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/backends/paddle.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/backends/tesseract.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/convert_impl.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/converter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/emit.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/io_util.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/image/utils.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/api/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/api/main.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/api/mcp_server.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/api/settings.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/api/zip_bundle.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/converter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/md_emit.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/pdf_extract.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/pdf/utils.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/api/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/api/convert_runner.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/api/jobs.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/api/main.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/api/mcp_server.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/api/mcp_setup.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/api/query_options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/api/settings.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/convert_impl.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/converter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/embedded_extract.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/ooxml_media.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/post_assets.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/text_formatting.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/vendor_pdf_md/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/vendor_pdf_md/convert.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/vendor_word_md/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/vendor_word_md/convert.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/ppt/zip_deep.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/api/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/api/convert_runner.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/api/jobs.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/api/main.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/api/mcp_server.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/api/mcp_setup.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/api/query_options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/api/settings.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/convert_impl.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/converter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/format_detect.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/md_emit_json.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/md_emit_txt.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/md_emit_xml.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/text/options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/api/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/api/convert_runner.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/api/jobs.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/api/main.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/api/mcp_server.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/api/mcp_setup.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/api/query_options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/api/settings.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/assets.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/convert_impl.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/converter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/crawl.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/extract.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/fetch.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/html_to_md.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/options.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/page_convert.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/post_convert_assets.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/url/robots_util.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/api/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/api/convert_util.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/api/jobs.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/api/main.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/api/mcp_server.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/artifact.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/converter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/word/settings.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/api/__init__.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/api/app.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/convert_config.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/converter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/converter_core.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/excel_reader.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/markdown_emitter.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/md_generator/xlsx/mcp_server.py +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/mdengine.egg-info/dependency_links.txt +0 -0
- {mdengine-0.2.2 → mdengine-0.4.0}/src/mdengine.egg-info/top_level.txt +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mdengine
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Convert PDF, Office, images, text/JSON/XML, ZIP archives, and web URLs to Markdown.
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Convert PDF, Office, images, audio, video, text/JSON/XML, ZIP archives, and web URLs to Markdown.
|
|
5
5
|
Author: mdengine contributors
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/vishal7090/md-generator
|
|
8
8
|
Project-URL: Repository, https://github.com/vishal7090/md-generator
|
|
9
9
|
Project-URL: Issues, https://github.com/vishal7090/md-generator/issues
|
|
10
|
-
Keywords: markdown,pdf,docx,pptx,xlsx,ocr,zip,url,html
|
|
10
|
+
Keywords: markdown,pdf,docx,pptx,xlsx,ocr,zip,url,html,youtube,playwright
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
13
|
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
@@ -68,6 +68,25 @@ Requires-Dist: Pillow>=10.0.0; extra == "url-full"
|
|
|
68
68
|
Requires-Dist: olefile>=0.47; extra == "url-full"
|
|
69
69
|
Requires-Dist: openpyxl>=3.1.0; extra == "url-full"
|
|
70
70
|
Requires-Dist: pytesseract>=0.3.10; extra == "url-full"
|
|
71
|
+
Provides-Extra: audio
|
|
72
|
+
Requires-Dist: openai-whisper>=20231117; extra == "audio"
|
|
73
|
+
Requires-Dist: imageio-ffmpeg>=0.5.1; extra == "audio"
|
|
74
|
+
Provides-Extra: video
|
|
75
|
+
Requires-Dist: openai-whisper>=20231117; extra == "video"
|
|
76
|
+
Requires-Dist: imageio-ffmpeg>=0.5.1; extra == "video"
|
|
77
|
+
Provides-Extra: youtube
|
|
78
|
+
Requires-Dist: youtube-transcript-api>=0.6.0; extra == "youtube"
|
|
79
|
+
Requires-Dist: httpx>=0.27.0; extra == "youtube"
|
|
80
|
+
Requires-Dist: beautifulsoup4>=4.12.0; extra == "youtube"
|
|
81
|
+
Requires-Dist: lxml>=5.0.0; extra == "youtube"
|
|
82
|
+
Provides-Extra: playwright
|
|
83
|
+
Requires-Dist: playwright>=1.49.0; extra == "playwright"
|
|
84
|
+
Requires-Dist: httpx>=0.27.0; extra == "playwright"
|
|
85
|
+
Requires-Dist: beautifulsoup4>=4.12.0; extra == "playwright"
|
|
86
|
+
Requires-Dist: lxml>=5.0.0; extra == "playwright"
|
|
87
|
+
Requires-Dist: markdownify>=0.14.0; extra == "playwright"
|
|
88
|
+
Requires-Dist: readability-lxml>=0.8.1; extra == "playwright"
|
|
89
|
+
Requires-Dist: Pillow>=10.0.0; extra == "playwright"
|
|
71
90
|
Provides-Extra: api
|
|
72
91
|
Requires-Dist: fastapi>=0.115.0; extra == "api"
|
|
73
92
|
Requires-Dist: uvicorn[standard]>=0.32.0; extra == "api"
|
|
@@ -80,9 +99,13 @@ Requires-Dist: fastmcp>=2.3.0; extra == "mcp"
|
|
|
80
99
|
Provides-Extra: dev
|
|
81
100
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
82
101
|
Requires-Dist: httpx>=0.27.0; extra == "dev"
|
|
102
|
+
Requires-Dist: beautifulsoup4>=4.12.0; extra == "dev"
|
|
103
|
+
Requires-Dist: lxml>=5.0.0; extra == "dev"
|
|
104
|
+
Requires-Dist: youtube-transcript-api>=0.6.0; extra == "dev"
|
|
83
105
|
Requires-Dist: mdengine[api]; extra == "dev"
|
|
84
106
|
Requires-Dist: mdengine[mcp]; extra == "dev"
|
|
85
107
|
Requires-Dist: mdengine[url]; extra == "dev"
|
|
108
|
+
Requires-Dist: mdengine[playwright]; extra == "dev"
|
|
86
109
|
Provides-Extra: all
|
|
87
110
|
Requires-Dist: pymupdf>=1.24.0; extra == "all"
|
|
88
111
|
Requires-Dist: pdfplumber>=0.11.0; extra == "all"
|
|
@@ -108,18 +131,19 @@ Requires-Dist: fastmcp>=2.3.0; extra == "all"
|
|
|
108
131
|
Requires-Dist: beautifulsoup4>=4.12.0; extra == "all"
|
|
109
132
|
Requires-Dist: lxml_html_clean>=0.4.0; extra == "all"
|
|
110
133
|
Requires-Dist: readability-lxml>=0.8.1; extra == "all"
|
|
134
|
+
Requires-Dist: youtube-transcript-api>=0.6.0; extra == "all"
|
|
111
135
|
Dynamic: license-file
|
|
112
136
|
|
|
113
137
|
# mdengine
|
|
114
138
|
|
|
115
|
-
Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**,
|
|
139
|
+
Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**, **ZIP archives**, and **audio / video** (Whisper transcription → Markdown) into **Markdown** (and related assets). Install only the extras you need; everything imports under the **`md_generator`** package.
|
|
116
140
|
|
|
117
141
|
- **PyPI name:** `mdengine` (import package: `md_generator`)
|
|
118
142
|
- **Source:** [github.com/vishal7090/md-generator](https://github.com/vishal7090/md-generator)
|
|
119
143
|
- **Python:** 3.10+
|
|
120
144
|
- **License:** [MIT](LICENSE)
|
|
121
145
|
|
|
122
|
-
**Quick links:** [On a new computer](#on-a-new-computer) · [Command-line execution](#command-line-execution) · [Python library](#python-library) · [HTTP API](#http-api-fastapi) · [MCP](#mcp-model-context-protocol) · [Development](#development) · [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
146
|
+
**Quick links:** [On a new computer](#on-a-new-computer) · [Command-line execution](#command-line-execution) · [Python library](#python-library) · [Audio and video](#audio-and-video-to-markdown) · [HTTP API](#http-api-fastapi) · [MCP](#mcp-model-context-protocol) · [Development](#development) · [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
123
147
|
|
|
124
148
|
---
|
|
125
149
|
|
|
@@ -186,6 +210,8 @@ pip install "mdengine[all]"
|
|
|
186
210
|
| `archive` | ZIP → Markdown layout (Pillow; optional tesseract for inline image OCR) |
|
|
187
211
|
| `url` | HTTP(S) HTML → Markdown (httpx, readability-lxml, markdownify, BeautifulSoup, lxml) |
|
|
188
212
|
| `url-full` | `url` plus PDF/Word/PPTX/XLSX/archive stack for **post-converting** downloaded linked files to Markdown |
|
|
213
|
+
| `audio` | **Audio → Markdown** via Whisper (`openai-whisper`); ships `imageio-ffmpeg` for a bundled **ffmpeg** when none is on `PATH` |
|
|
214
|
+
| `video` | **Video → Markdown** (ffmpeg extracts mono 16 kHz WAV, then same Whisper stack as `audio`) |
|
|
189
215
|
| `api` | FastAPI, uvicorn, httpx, pydantic-settings |
|
|
190
216
|
| `mcp` | MCP servers (`mcp`, `fastmcp` where used) |
|
|
191
217
|
| `dev` | pytest + API/MCP test helpers |
|
|
@@ -228,6 +254,15 @@ If the shell reports “command not found”, ensure the Python **Scripts** dire
|
|
|
228
254
|
| `md-text` | `md_generator.text.converter:main` | `md-text config.xml out.md` |
|
|
229
255
|
| `md-zip` | `md_generator.archive.converter:main` | `md-zip bundle.zip ./zip-out` |
|
|
230
256
|
| `md-url` | `md_generator.url.converter:main` | `md-url https://example.com/doc ./web-out --artifact-layout` |
|
|
257
|
+
| `md-audio` | `md_generator.media.audio.converter:main` | `md-audio clip.mp3 transcript.md --model base` |
|
|
258
|
+
| `md-video` | `md_generator.media.video.converter:main` | `md-video clip.mp4 transcript.md --model base` |
|
|
259
|
+
| `md-youtube` | `md_generator.media.youtube.converter:main` | `md-youtube "https://youtu.be/…" out.md --transcript-lang en` |
|
|
260
|
+
| `md-audio-api` | `md_generator.media.audio.api.run:main` | REST + MCP on port **8011** (see [Audio and video to Markdown](#audio-and-video-to-markdown)) |
|
|
261
|
+
| `md-video-api` | `md_generator.media.video.api.run:main` | REST + MCP on port **8012** |
|
|
262
|
+
| `md-youtube-api` | `md_generator.media.youtube.api.run:main` | REST + MCP on port **8013** (JSON `url` body; see same section) |
|
|
263
|
+
| `md-audio-mcp` | `md_generator.media.audio.api.mcp_server:main` | Standalone MCP (`--transport stdio` \| `sse` \| `streamable-http`) |
|
|
264
|
+
| `md-video-mcp` | `md_generator.media.video.api.mcp_server:main` | Same for video |
|
|
265
|
+
| `md-youtube-mcp` | `md_generator.media.youtube.api.mcp_server:main` | Same for YouTube (`youtube_url_to_markdown`) |
|
|
231
266
|
|
|
232
267
|
Every command accepts **`-h` / `--help`** for full flags (artifact layout, OCR, ZIP options, etc.).
|
|
233
268
|
|
|
@@ -245,6 +280,8 @@ md-image ./photos ocr.md --engines tess --strategy best
|
|
|
245
280
|
md-text data.json data.md
|
|
246
281
|
md-zip archive.zip ./unzipped-md
|
|
247
282
|
md-url https://example.com/page ./page-bundle --artifact-layout
|
|
283
|
+
md-audio ./voice.mp3 ./voice.md --model tiny
|
|
284
|
+
md-video ./screen.mp4 ./screen.md --model base
|
|
248
285
|
```
|
|
249
286
|
|
|
250
287
|
**Windows PowerShell** (same commands; use backslashes for paths if you prefer)
|
|
@@ -253,6 +290,8 @@ md-url https://example.com/page ./page-bundle --artifact-layout
|
|
|
253
290
|
md-pdf .\manual.pdf .\out\doc.md
|
|
254
291
|
md-zip .\archive.zip .\zip-out
|
|
255
292
|
md-url https://example.com/page .\page-bundle --artifact-layout
|
|
293
|
+
md-audio .\voice.mp3 .\voice.md --model tiny
|
|
294
|
+
md-video .\screen.mp4 .\screen.md --model base
|
|
256
295
|
```
|
|
257
296
|
|
|
258
297
|
**Windows CMD**
|
|
@@ -422,6 +461,124 @@ convert_zip(
|
|
|
422
461
|
|
|
423
462
|
---
|
|
424
463
|
|
|
464
|
+
## Audio and video to Markdown
|
|
465
|
+
|
|
466
|
+
Library code lives under **`md_generator.media`**: shared probing in [`document_converter.py`](src/md_generator/media/document_converter.py), **audio** in [`media/audio/`](src/md_generator/media/audio/) (Whisper + ffprobe / ffmpeg metadata), **video** in [`media/video/`](src/md_generator/media/video/) (ffmpeg extracts audio only; transcription always goes through the audio service—no duplicate Whisper path in video).
|
|
467
|
+
|
|
468
|
+
### System requirements
|
|
469
|
+
|
|
470
|
+
- **ffmpeg** (and **ffprobe** when available) on `PATH` for metadata and for **video** demux. If `ffprobe` is missing or misbehaving, metadata falls back to parsing `ffmpeg -i` stderr.
|
|
471
|
+
- Optional **`FFMPEG`** environment variable: absolute path to an `ffmpeg` executable (see [`resolve_ffmpeg_executable()`](src/md_generator/media/document_converter.py)).
|
|
472
|
+
- **GPU** is optional; Whisper runs on CPU if needed (may log FP16→FP32 on CPU).
|
|
473
|
+
|
|
474
|
+
### Install
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
pip install "mdengine[audio,api,mcp]" # audio CLI + HTTP + MCP
|
|
478
|
+
pip install "mdengine[video,api,mcp]" # video CLI + HTTP + MCP (same ML stack as audio)
|
|
479
|
+
pip install "mdengine[youtube,api,mcp]" # YouTube URL → Markdown (captions + metadata; optional Whisper fallback)
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### Python library
|
|
483
|
+
|
|
484
|
+
**Audio** — structured result + Markdown:
|
|
485
|
+
|
|
486
|
+
```python
|
|
487
|
+
from pathlib import Path
|
|
488
|
+
from md_generator.media.audio import AudioToMarkdownService, AudioConverter
|
|
489
|
+
|
|
490
|
+
svc = AudioToMarkdownService(whisper_model="base") # language omitted → Whisper auto-detect; pass e.g. language="en" to force
|
|
491
|
+
text = svc.to_markdown(Path("input.mp3"), title="My title")
|
|
492
|
+
svc.write_markdown(Path("input.mp3"), Path("out/transcript.md"))
|
|
493
|
+
|
|
494
|
+
result = svc.transcribe(Path("input.wav")) # metadata + segments + plain_text
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
**Video** — extract → transcribe (via audio) → Markdown:
|
|
498
|
+
|
|
499
|
+
```python
|
|
500
|
+
from pathlib import Path
|
|
501
|
+
from md_generator.media.video import VideoToMarkdownService
|
|
502
|
+
|
|
503
|
+
svc = VideoToMarkdownService(whisper_model="base") # transcription language omitted → auto-detect
|
|
504
|
+
md = svc.to_markdown(Path("input.mp4"), title=None)
|
|
505
|
+
svc.write_markdown(Path("input.mp4"), Path("out/transcript.md"))
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
**YouTube** — captions API + page metadata (BeautifulSoup / oEmbed); optional **yt-dlp + Whisper** when captions are missing (`mdengine[audio]` and `yt-dlp` on `PATH`, or `MD_YOUTUBE_YTDLP`):
|
|
509
|
+
|
|
510
|
+
```python
|
|
511
|
+
from md_generator.media.youtube import YouTubeToMarkdownService
|
|
512
|
+
|
|
513
|
+
svc = YouTubeToMarkdownService(whisper_model="base")
|
|
514
|
+
md = svc.to_markdown("https://www.youtube.com/watch?v=VIDEO_ID", transcript_languages=["en"])
|
|
515
|
+
svc.write_markdown("https://youtu.be/VIDEO_ID", Path("out/youtube.md"))
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
For file-based pipelines, [`YouTubeConverter`](src/md_generator/media/youtube/converter.py) reads a `.url` / `.yturl` / `.youtube` file (or a `.txt` whose first non-comment line is a YouTube URL) and implements [`DocumentConverter`](src/md_generator/media/document_converter.py).
|
|
519
|
+
|
|
520
|
+
Public symbols are also re-exported from [`md_generator.media`](src/md_generator/media/__init__.py) for ffprobe helpers (`ffprobe_json`, `VideoProbeResult`, …).
|
|
521
|
+
|
|
522
|
+
### REST API (FastAPI)
|
|
523
|
+
|
|
524
|
+
Each service exposes the same job pattern as other converters:
|
|
525
|
+
|
|
526
|
+
| Endpoint | Description |
|
|
527
|
+
|----------|-------------|
|
|
528
|
+
| `POST /convert/sync` | Multipart field **`file`**; returns **Markdown** body. Query: `whisper_model`, `language` (omit or `auto` for detection; pass a code to force), `title`. |
|
|
529
|
+
| `POST /convert/jobs` | Async upload; returns `{ "job_id", "status" }`. |
|
|
530
|
+
| `GET /convert/jobs/{job_id}` | Status JSON. |
|
|
531
|
+
| `GET /convert/jobs/{job_id}/download` | Markdown when `done`; workspace removed after download. |
|
|
532
|
+
|
|
533
|
+
**Audio** defaults: `MD_AUDIO_MAX_UPLOAD_MB=200`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB=40`, `MD_AUDIO_API_PORT=8011`.
|
|
534
|
+
**Video** defaults: `MD_VIDEO_MAX_UPLOAD_MB=500`, `MD_VIDEO_MAX_SYNC_UPLOAD_MB=80`, `MD_VIDEO_API_PORT=8012`.
|
|
535
|
+
**YouTube** uses **JSON** (not multipart): `POST /convert/sync` and `POST /convert/jobs` accept `{"url":"https://www.youtube.com/watch?v=…","title":null,"transcript_languages":["en"],"enable_audio_fallback":true,"whisper_model":"base","language":null}`. Defaults: `MD_YOUTUBE_API_PORT=8013`, `MD_YOUTUBE_JOB_TTL_SECONDS`, `MD_YOUTUBE_CORS_ORIGINS`, `MD_YOUTUBE_TEMP_DIR`.
|
|
536
|
+
|
|
537
|
+
Run with the bundled runners (each call builds the app with **`factory=True`** for a clean MCP session manager):
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
md-audio-api --host 127.0.0.1 --port 8011
|
|
541
|
+
md-video-api --host 127.0.0.1 --port 8012
|
|
542
|
+
md-youtube-api --host 127.0.0.1 --port 8013
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Or with Uvicorn directly (the ASGI app is built by **`create_app()`** so each worker gets its own MCP session manager):
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
|
|
549
|
+
uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
|
|
550
|
+
uvicorn md_generator.media.youtube.api.main:create_app --factory --host 127.0.0.1 --port 8013
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
The module also defines **`app = create_app()`** for a single-process target: `uvicorn md_generator.media.audio.api.main:app` (no `--factory`).
|
|
554
|
+
|
|
555
|
+
Swagger is at **`/docs`** when the app is running.
|
|
556
|
+
|
|
557
|
+
### MCP (stdio, SSE, streamable HTTP)
|
|
558
|
+
|
|
559
|
+
1. **With FastAPI** — start `md-audio-api`, `md-video-api`, or `md-youtube-api`; mount Streamable HTTP MCP at **`http://<host>:<port>/mcp`** (same host as REST).
|
|
560
|
+
2. **Standalone** — process speaks MCP only:
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
md-audio-mcp --transport stdio
|
|
564
|
+
md-audio-mcp --transport sse
|
|
565
|
+
md-audio-mcp --transport streamable-http
|
|
566
|
+
md-video-mcp --transport stdio
|
|
567
|
+
md-youtube-mcp --transport stdio
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**Audio MCP tools:** `transcribe_audio_path`, `transcribe_audio_base64`.
|
|
571
|
+
**Video MCP tools:** `transcribe_video_path`, `transcribe_video_base64`.
|
|
572
|
+
**YouTube MCP tool:** `youtube_url_to_markdown`.
|
|
573
|
+
|
|
574
|
+
Equivalent modules: `python -m md_generator.media.audio.api.mcp_server`, `python -m md_generator.media.video.api.mcp_server`, `python -m md_generator.media.youtube.api.mcp_server`.
|
|
575
|
+
|
|
576
|
+
### Thin shims (repo clone)
|
|
577
|
+
|
|
578
|
+
[`audio-to-md/converter.py`](audio-to-md/converter.py), [`video-to-md/converter.py`](video-to-md/converter.py), and [`youtube-to-md/converter.py`](youtube-to-md/converter.py) delegate to the same `main` as `md-audio` / `md-video` / `md-youtube`. Tests and `pytest.ini` live under `audio-to-md/tests/`, `video-to-md/tests/`, and `youtube-to-md/tests/`.
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
425
582
|
## HTTP API (FastAPI)
|
|
426
583
|
|
|
427
584
|
All format APIs follow a similar pattern:
|
|
@@ -447,6 +604,10 @@ Install `mdengine[api]` plus the format extra(s), then run the **`app`** object
|
|
|
447
604
|
| Text/JSON/XML | `md_generator.text.api.main:app` | `text`, `api`, `mcp` |
|
|
448
605
|
| ZIP | `md_generator.archive.api.main:app` | `archive`, `api`, `mcp` (+ extras for nested office/PDF) |
|
|
449
606
|
| URL / HTML | `md_generator.url.api.main:app` | `url`, `api`, `mcp` |
|
|
607
|
+
| Playwright / SPA | `md_generator.playwright.api.main:app` | `playwright`, `api`, `mcp` |
|
|
608
|
+
| Audio (Whisper) | `md_generator.media.audio.api.main:create_app` (use **`--factory`**) or `…main:app` | `audio`, `api`, `mcp` |
|
|
609
|
+
| Video (Whisper) | `md_generator.media.video.api.main:create_app` (use **`--factory`**) or `…main:app` | `video`, `api`, `mcp` |
|
|
610
|
+
| YouTube | `md_generator.media.youtube.api.main:create_app` (use **`--factory`**) or `…main:app` | `youtube`, `api`, `mcp` |
|
|
450
611
|
|
|
451
612
|
Examples:
|
|
452
613
|
|
|
@@ -455,6 +616,10 @@ uvicorn md_generator.pdf.api.main:app --host 127.0.0.1 --port 8001
|
|
|
455
616
|
uvicorn md_generator.word.api.main:app --host 127.0.0.1 --port 8002
|
|
456
617
|
uvicorn md_generator.archive.api.main:app --host 127.0.0.1 --port 8010
|
|
457
618
|
uvicorn md_generator.url.api.main:app --host 127.0.0.1 --port 8011
|
|
619
|
+
uvicorn md_generator.playwright.api.main:app --host 127.0.0.1 --port 8014
|
|
620
|
+
uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
|
|
621
|
+
uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
|
|
622
|
+
uvicorn md_generator.media.youtube.api.main:create_app --factory --host 127.0.0.1 --port 8013
|
|
458
623
|
```
|
|
459
624
|
|
|
460
625
|
### MCP over HTTP on the same server
|
|
@@ -474,6 +639,10 @@ Prefixes differ per service (often read from a `.env` file next to the process):
|
|
|
474
639
|
| Text | `TXT_JSON_XML_TO_MD_` | same pattern |
|
|
475
640
|
| XLSX | `XLSX_TO_MD_` | `XLSX_TO_MD_TEMP_DIR`, `XLSX_TO_MD_CORS_ORIGINS`, etc. (see `md_generator.xlsx.api.app`) |
|
|
476
641
|
| URL | `URL_TO_MD_` | `URL_TO_MD_MAX_SYNC_URLS`, `URL_TO_MD_MAX_SYNC_CRAWL_PAGES`, `URL_TO_MD_MAX_JOB_URLS`, `URL_TO_MD_JOB_TTL_SECONDS`, `URL_TO_MD_TEMP_DIR`, `URL_TO_MD_CORS_ORIGINS` |
|
|
642
|
+
| Playwright / SPA | `PLAYWRIGHT_TO_MD_` | `PLAYWRIGHT_TO_MD_MAX_SYNC_URLS`, `PLAYWRIGHT_TO_MD_MAX_JOB_URLS`, `PLAYWRIGHT_TO_MD_JOB_TTL_SECONDS`, `PLAYWRIGHT_TO_MD_TEMP_DIR`, `PLAYWRIGHT_TO_MD_CORS_ORIGINS`, `PLAYWRIGHT_TO_MD_API_HOST`, `PLAYWRIGHT_TO_MD_API_PORT` (default **8014**) |
|
|
643
|
+
| Audio API | `MD_AUDIO_` | `MD_AUDIO_MAX_UPLOAD_MB`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB`, `MD_AUDIO_JOB_TTL_SECONDS`, `MD_AUDIO_TEMP_DIR`, `MD_AUDIO_CORS_ORIGINS`, `MD_AUDIO_API_HOST`, `MD_AUDIO_API_PORT` |
|
|
644
|
+
| Video API | `MD_VIDEO_` | Same pattern as audio with `MD_VIDEO_*` (defaults: larger upload/sync caps, port **8012**) |
|
|
645
|
+
| YouTube API | `MD_YOUTUBE_` | `MD_YOUTUBE_JOB_TTL_SECONDS`, `MD_YOUTUBE_TEMP_DIR`, `MD_YOUTUBE_CORS_ORIGINS`, `MD_YOUTUBE_API_HOST`, `MD_YOUTUBE_API_PORT` (default **8013**); optional `MD_YOUTUBE_YTDLP` path for audio fallback |
|
|
477
646
|
|
|
478
647
|
Exact variable names match the `ApiSettings` / helper functions in each `api/settings` or `api/app` module.
|
|
479
648
|
|
|
@@ -497,6 +666,10 @@ Two usage patterns:
|
|
|
497
666
|
| PPTX | `python -m md_generator.ppt.api.mcp_server` (see module docstring for flags) |
|
|
498
667
|
| Image | `python -m md_generator.image.api.mcp_server` (see module for CLI) |
|
|
499
668
|
| URL / HTML | `python -m md_generator.url.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
|
|
669
|
+
| Playwright / SPA | `md-playwright-mcp` or `python -m md_generator.playwright.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
|
|
670
|
+
| Audio | `md-audio-mcp` or `python -m md_generator.media.audio.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
|
|
671
|
+
| Video | `md-video-mcp` or `python -m md_generator.media.video.api.mcp_server` — same transports |
|
|
672
|
+
| YouTube | `md-youtube-mcp` or `python -m md_generator.media.youtube.api.mcp_server` — same transports |
|
|
500
673
|
|
|
501
674
|
**Word** and **XLSX** also ship a small runner script in the repo:
|
|
502
675
|
|
|
@@ -531,7 +704,7 @@ Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/test
|
|
|
531
704
|
|------|------|
|
|
532
705
|
| `LICENSE` | MIT license text |
|
|
533
706
|
| `CODE_OF_CONDUCT.md` | [Contributor Covenant](https://www.contributor-covenant.org/) 2.1 |
|
|
534
|
-
| `src/md_generator/` | **Library source** (all formats + `api` subpackages) |
|
|
707
|
+
| `src/md_generator/` | **Library source** (all formats + `api` subpackages); **audio/video** under [`media/audio/`](src/md_generator/media/audio/) and [`media/video/`](src/md_generator/media/video/) |
|
|
535
708
|
| `pyproject.toml` | Packaging, extras, CLI entry points, pytest |
|
|
536
709
|
| `*-to-md/` | **Docs, tests, fixtures**, thin `converter.py` shims, some `run.py` helpers |
|
|
537
710
|
| `README.md` | This document |
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# mdengine
|
|
2
2
|
|
|
3
|
-
Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**,
|
|
3
|
+
Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**, **ZIP archives**, and **audio / video** (Whisper transcription → Markdown) into **Markdown** (and related assets). Install only the extras you need; everything imports under the **`md_generator`** package.
|
|
4
4
|
|
|
5
5
|
- **PyPI name:** `mdengine` (import package: `md_generator`)
|
|
6
6
|
- **Source:** [github.com/vishal7090/md-generator](https://github.com/vishal7090/md-generator)
|
|
7
7
|
- **Python:** 3.10+
|
|
8
8
|
- **License:** [MIT](LICENSE)
|
|
9
9
|
|
|
10
|
-
**Quick links:** [On a new computer](#on-a-new-computer) · [Command-line execution](#command-line-execution) · [Python library](#python-library) · [HTTP API](#http-api-fastapi) · [MCP](#mcp-model-context-protocol) · [Development](#development) · [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
10
|
+
**Quick links:** [On a new computer](#on-a-new-computer) · [Command-line execution](#command-line-execution) · [Python library](#python-library) · [Audio and video](#audio-and-video-to-markdown) · [HTTP API](#http-api-fastapi) · [MCP](#mcp-model-context-protocol) · [Development](#development) · [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -74,6 +74,8 @@ pip install "mdengine[all]"
|
|
|
74
74
|
| `archive` | ZIP → Markdown layout (Pillow; optional tesseract for inline image OCR) |
|
|
75
75
|
| `url` | HTTP(S) HTML → Markdown (httpx, readability-lxml, markdownify, BeautifulSoup, lxml) |
|
|
76
76
|
| `url-full` | `url` plus PDF/Word/PPTX/XLSX/archive stack for **post-converting** downloaded linked files to Markdown |
|
|
77
|
+
| `audio` | **Audio → Markdown** via Whisper (`openai-whisper`); ships `imageio-ffmpeg` for a bundled **ffmpeg** when none is on `PATH` |
|
|
78
|
+
| `video` | **Video → Markdown** (ffmpeg extracts mono 16 kHz WAV, then same Whisper stack as `audio`) |
|
|
77
79
|
| `api` | FastAPI, uvicorn, httpx, pydantic-settings |
|
|
78
80
|
| `mcp` | MCP servers (`mcp`, `fastmcp` where used) |
|
|
79
81
|
| `dev` | pytest + API/MCP test helpers |
|
|
@@ -116,6 +118,15 @@ If the shell reports “command not found”, ensure the Python **Scripts** dire
|
|
|
116
118
|
| `md-text` | `md_generator.text.converter:main` | `md-text config.xml out.md` |
|
|
117
119
|
| `md-zip` | `md_generator.archive.converter:main` | `md-zip bundle.zip ./zip-out` |
|
|
118
120
|
| `md-url` | `md_generator.url.converter:main` | `md-url https://example.com/doc ./web-out --artifact-layout` |
|
|
121
|
+
| `md-audio` | `md_generator.media.audio.converter:main` | `md-audio clip.mp3 transcript.md --model base` |
|
|
122
|
+
| `md-video` | `md_generator.media.video.converter:main` | `md-video clip.mp4 transcript.md --model base` |
|
|
123
|
+
| `md-youtube` | `md_generator.media.youtube.converter:main` | `md-youtube "https://youtu.be/…" out.md --transcript-lang en` |
|
|
124
|
+
| `md-audio-api` | `md_generator.media.audio.api.run:main` | REST + MCP on port **8011** (see [Audio and video to Markdown](#audio-and-video-to-markdown)) |
|
|
125
|
+
| `md-video-api` | `md_generator.media.video.api.run:main` | REST + MCP on port **8012** |
|
|
126
|
+
| `md-youtube-api` | `md_generator.media.youtube.api.run:main` | REST + MCP on port **8013** (JSON `url` body; see same section) |
|
|
127
|
+
| `md-audio-mcp` | `md_generator.media.audio.api.mcp_server:main` | Standalone MCP (`--transport stdio` \| `sse` \| `streamable-http`) |
|
|
128
|
+
| `md-video-mcp` | `md_generator.media.video.api.mcp_server:main` | Same for video |
|
|
129
|
+
| `md-youtube-mcp` | `md_generator.media.youtube.api.mcp_server:main` | Same for YouTube (`youtube_url_to_markdown`) |
|
|
119
130
|
|
|
120
131
|
Every command accepts **`-h` / `--help`** for full flags (artifact layout, OCR, ZIP options, etc.).
|
|
121
132
|
|
|
@@ -133,6 +144,8 @@ md-image ./photos ocr.md --engines tess --strategy best
|
|
|
133
144
|
md-text data.json data.md
|
|
134
145
|
md-zip archive.zip ./unzipped-md
|
|
135
146
|
md-url https://example.com/page ./page-bundle --artifact-layout
|
|
147
|
+
md-audio ./voice.mp3 ./voice.md --model tiny
|
|
148
|
+
md-video ./screen.mp4 ./screen.md --model base
|
|
136
149
|
```
|
|
137
150
|
|
|
138
151
|
**Windows PowerShell** (same commands; use backslashes for paths if you prefer)
|
|
@@ -141,6 +154,8 @@ md-url https://example.com/page ./page-bundle --artifact-layout
|
|
|
141
154
|
md-pdf .\manual.pdf .\out\doc.md
|
|
142
155
|
md-zip .\archive.zip .\zip-out
|
|
143
156
|
md-url https://example.com/page .\page-bundle --artifact-layout
|
|
157
|
+
md-audio .\voice.mp3 .\voice.md --model tiny
|
|
158
|
+
md-video .\screen.mp4 .\screen.md --model base
|
|
144
159
|
```
|
|
145
160
|
|
|
146
161
|
**Windows CMD**
|
|
@@ -310,6 +325,124 @@ convert_zip(
|
|
|
310
325
|
|
|
311
326
|
---
|
|
312
327
|
|
|
328
|
+
## Audio and video to Markdown
|
|
329
|
+
|
|
330
|
+
Library code lives under **`md_generator.media`**: shared probing in [`document_converter.py`](src/md_generator/media/document_converter.py), **audio** in [`media/audio/`](src/md_generator/media/audio/) (Whisper + ffprobe / ffmpeg metadata), **video** in [`media/video/`](src/md_generator/media/video/) (ffmpeg extracts audio only; transcription always goes through the audio service—no duplicate Whisper path in video).
|
|
331
|
+
|
|
332
|
+
### System requirements
|
|
333
|
+
|
|
334
|
+
- **ffmpeg** (and **ffprobe** when available) on `PATH` for metadata and for **video** demux. If `ffprobe` is missing or misbehaving, metadata falls back to parsing `ffmpeg -i` stderr.
|
|
335
|
+
- Optional **`FFMPEG`** environment variable: absolute path to an `ffmpeg` executable (see [`resolve_ffmpeg_executable()`](src/md_generator/media/document_converter.py)).
|
|
336
|
+
- **GPU** is optional; Whisper runs on CPU if needed (may log FP16→FP32 on CPU).
|
|
337
|
+
|
|
338
|
+
### Install
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
pip install "mdengine[audio,api,mcp]" # audio CLI + HTTP + MCP
|
|
342
|
+
pip install "mdengine[video,api,mcp]" # video CLI + HTTP + MCP (same ML stack as audio)
|
|
343
|
+
pip install "mdengine[youtube,api,mcp]" # YouTube URL → Markdown (captions + metadata; optional Whisper fallback)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Python library
|
|
347
|
+
|
|
348
|
+
**Audio** — structured result + Markdown:
|
|
349
|
+
|
|
350
|
+
```python
|
|
351
|
+
from pathlib import Path
|
|
352
|
+
from md_generator.media.audio import AudioToMarkdownService, AudioConverter
|
|
353
|
+
|
|
354
|
+
svc = AudioToMarkdownService(whisper_model="base") # language omitted → Whisper auto-detect; pass e.g. language="en" to force
|
|
355
|
+
text = svc.to_markdown(Path("input.mp3"), title="My title")
|
|
356
|
+
svc.write_markdown(Path("input.mp3"), Path("out/transcript.md"))
|
|
357
|
+
|
|
358
|
+
result = svc.transcribe(Path("input.wav")) # metadata + segments + plain_text
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Video** — extract → transcribe (via audio) → Markdown:
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
from pathlib import Path
|
|
365
|
+
from md_generator.media.video import VideoToMarkdownService
|
|
366
|
+
|
|
367
|
+
svc = VideoToMarkdownService(whisper_model="base") # transcription language omitted → auto-detect
|
|
368
|
+
md = svc.to_markdown(Path("input.mp4"), title=None)
|
|
369
|
+
svc.write_markdown(Path("input.mp4"), Path("out/transcript.md"))
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**YouTube** — captions API + page metadata (BeautifulSoup / oEmbed); optional **yt-dlp + Whisper** when captions are missing (`mdengine[audio]` and `yt-dlp` on `PATH`, or `MD_YOUTUBE_YTDLP`):
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
from md_generator.media.youtube import YouTubeToMarkdownService
|
|
376
|
+
|
|
377
|
+
svc = YouTubeToMarkdownService(whisper_model="base")
|
|
378
|
+
md = svc.to_markdown("https://www.youtube.com/watch?v=VIDEO_ID", transcript_languages=["en"])
|
|
379
|
+
svc.write_markdown("https://youtu.be/VIDEO_ID", Path("out/youtube.md"))
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
For file-based pipelines, [`YouTubeConverter`](src/md_generator/media/youtube/converter.py) reads a `.url` / `.yturl` / `.youtube` file (or a `.txt` whose first non-comment line is a YouTube URL) and implements [`DocumentConverter`](src/md_generator/media/document_converter.py).
|
|
383
|
+
|
|
384
|
+
Public symbols are also re-exported from [`md_generator.media`](src/md_generator/media/__init__.py) for ffprobe helpers (`ffprobe_json`, `VideoProbeResult`, …).
|
|
385
|
+
|
|
386
|
+
### REST API (FastAPI)
|
|
387
|
+
|
|
388
|
+
Each service exposes the same job pattern as other converters:
|
|
389
|
+
|
|
390
|
+
| Endpoint | Description |
|
|
391
|
+
|----------|-------------|
|
|
392
|
+
| `POST /convert/sync` | Multipart field **`file`**; returns **Markdown** body. Query: `whisper_model`, `language` (omit or `auto` for detection; pass a code to force), `title`. |
|
|
393
|
+
| `POST /convert/jobs` | Async upload; returns `{ "job_id", "status" }`. |
|
|
394
|
+
| `GET /convert/jobs/{job_id}` | Status JSON. |
|
|
395
|
+
| `GET /convert/jobs/{job_id}/download` | Markdown when `done`; workspace removed after download. |
|
|
396
|
+
|
|
397
|
+
**Audio** defaults: `MD_AUDIO_MAX_UPLOAD_MB=200`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB=40`, `MD_AUDIO_API_PORT=8011`.
|
|
398
|
+
**Video** defaults: `MD_VIDEO_MAX_UPLOAD_MB=500`, `MD_VIDEO_MAX_SYNC_UPLOAD_MB=80`, `MD_VIDEO_API_PORT=8012`.
|
|
399
|
+
**YouTube** uses **JSON** (not multipart): `POST /convert/sync` and `POST /convert/jobs` accept `{"url":"https://www.youtube.com/watch?v=…","title":null,"transcript_languages":["en"],"enable_audio_fallback":true,"whisper_model":"base","language":null}`. Defaults: `MD_YOUTUBE_API_PORT=8013`, `MD_YOUTUBE_JOB_TTL_SECONDS`, `MD_YOUTUBE_CORS_ORIGINS`, `MD_YOUTUBE_TEMP_DIR`.
|
|
400
|
+
|
|
401
|
+
Run with the bundled runners (each call builds the app with **`factory=True`** for a clean MCP session manager):
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
md-audio-api --host 127.0.0.1 --port 8011
|
|
405
|
+
md-video-api --host 127.0.0.1 --port 8012
|
|
406
|
+
md-youtube-api --host 127.0.0.1 --port 8013
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Or with Uvicorn directly (the ASGI app is built by **`create_app()`** so each worker gets its own MCP session manager):
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
|
|
413
|
+
uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
|
|
414
|
+
uvicorn md_generator.media.youtube.api.main:create_app --factory --host 127.0.0.1 --port 8013
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
The module also defines **`app = create_app()`** for a single-process target: `uvicorn md_generator.media.audio.api.main:app` (no `--factory`).
|
|
418
|
+
|
|
419
|
+
Swagger is at **`/docs`** when the app is running.
|
|
420
|
+
|
|
421
|
+
### MCP (stdio, SSE, streamable HTTP)
|
|
422
|
+
|
|
423
|
+
1. **With FastAPI** — start `md-audio-api`, `md-video-api`, or `md-youtube-api`; mount Streamable HTTP MCP at **`http://<host>:<port>/mcp`** (same host as REST).
|
|
424
|
+
2. **Standalone** — process speaks MCP only:
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
md-audio-mcp --transport stdio
|
|
428
|
+
md-audio-mcp --transport sse
|
|
429
|
+
md-audio-mcp --transport streamable-http
|
|
430
|
+
md-video-mcp --transport stdio
|
|
431
|
+
md-youtube-mcp --transport stdio
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**Audio MCP tools:** `transcribe_audio_path`, `transcribe_audio_base64`.
|
|
435
|
+
**Video MCP tools:** `transcribe_video_path`, `transcribe_video_base64`.
|
|
436
|
+
**YouTube MCP tool:** `youtube_url_to_markdown`.
|
|
437
|
+
|
|
438
|
+
Equivalent modules: `python -m md_generator.media.audio.api.mcp_server`, `python -m md_generator.media.video.api.mcp_server`, `python -m md_generator.media.youtube.api.mcp_server`.
|
|
439
|
+
|
|
440
|
+
### Thin shims (repo clone)
|
|
441
|
+
|
|
442
|
+
[`audio-to-md/converter.py`](audio-to-md/converter.py), [`video-to-md/converter.py`](video-to-md/converter.py), and [`youtube-to-md/converter.py`](youtube-to-md/converter.py) delegate to the same `main` as `md-audio` / `md-video` / `md-youtube`. Tests and `pytest.ini` live under `audio-to-md/tests/`, `video-to-md/tests/`, and `youtube-to-md/tests/`.
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
313
446
|
## HTTP API (FastAPI)
|
|
314
447
|
|
|
315
448
|
All format APIs follow a similar pattern:
|
|
@@ -335,6 +468,10 @@ Install `mdengine[api]` plus the format extra(s), then run the **`app`** object
|
|
|
335
468
|
| Text/JSON/XML | `md_generator.text.api.main:app` | `text`, `api`, `mcp` |
|
|
336
469
|
| ZIP | `md_generator.archive.api.main:app` | `archive`, `api`, `mcp` (+ extras for nested office/PDF) |
|
|
337
470
|
| URL / HTML | `md_generator.url.api.main:app` | `url`, `api`, `mcp` |
|
|
471
|
+
| Playwright / SPA | `md_generator.playwright.api.main:app` | `playwright`, `api`, `mcp` |
|
|
472
|
+
| Audio (Whisper) | `md_generator.media.audio.api.main:create_app` (use **`--factory`**) or `…main:app` | `audio`, `api`, `mcp` |
|
|
473
|
+
| Video (Whisper) | `md_generator.media.video.api.main:create_app` (use **`--factory`**) or `…main:app` | `video`, `api`, `mcp` |
|
|
474
|
+
| YouTube | `md_generator.media.youtube.api.main:create_app` (use **`--factory`**) or `…main:app` | `youtube`, `api`, `mcp` |
|
|
338
475
|
|
|
339
476
|
Examples:
|
|
340
477
|
|
|
@@ -343,6 +480,10 @@ uvicorn md_generator.pdf.api.main:app --host 127.0.0.1 --port 8001
|
|
|
343
480
|
uvicorn md_generator.word.api.main:app --host 127.0.0.1 --port 8002
|
|
344
481
|
uvicorn md_generator.archive.api.main:app --host 127.0.0.1 --port 8010
|
|
345
482
|
uvicorn md_generator.url.api.main:app --host 127.0.0.1 --port 8011
|
|
483
|
+
uvicorn md_generator.playwright.api.main:app --host 127.0.0.1 --port 8014
|
|
484
|
+
uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
|
|
485
|
+
uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
|
|
486
|
+
uvicorn md_generator.media.youtube.api.main:create_app --factory --host 127.0.0.1 --port 8013
|
|
346
487
|
```
|
|
347
488
|
|
|
348
489
|
### MCP over HTTP on the same server
|
|
@@ -362,6 +503,10 @@ Prefixes differ per service (often read from a `.env` file next to the process):
|
|
|
362
503
|
| Text | `TXT_JSON_XML_TO_MD_` | same pattern |
|
|
363
504
|
| XLSX | `XLSX_TO_MD_` | `XLSX_TO_MD_TEMP_DIR`, `XLSX_TO_MD_CORS_ORIGINS`, etc. (see `md_generator.xlsx.api.app`) |
|
|
364
505
|
| URL | `URL_TO_MD_` | `URL_TO_MD_MAX_SYNC_URLS`, `URL_TO_MD_MAX_SYNC_CRAWL_PAGES`, `URL_TO_MD_MAX_JOB_URLS`, `URL_TO_MD_JOB_TTL_SECONDS`, `URL_TO_MD_TEMP_DIR`, `URL_TO_MD_CORS_ORIGINS` |
|
|
506
|
+
| Playwright / SPA | `PLAYWRIGHT_TO_MD_` | `PLAYWRIGHT_TO_MD_MAX_SYNC_URLS`, `PLAYWRIGHT_TO_MD_MAX_JOB_URLS`, `PLAYWRIGHT_TO_MD_JOB_TTL_SECONDS`, `PLAYWRIGHT_TO_MD_TEMP_DIR`, `PLAYWRIGHT_TO_MD_CORS_ORIGINS`, `PLAYWRIGHT_TO_MD_API_HOST`, `PLAYWRIGHT_TO_MD_API_PORT` (default **8014**) |
|
|
507
|
+
| Audio API | `MD_AUDIO_` | `MD_AUDIO_MAX_UPLOAD_MB`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB`, `MD_AUDIO_JOB_TTL_SECONDS`, `MD_AUDIO_TEMP_DIR`, `MD_AUDIO_CORS_ORIGINS`, `MD_AUDIO_API_HOST`, `MD_AUDIO_API_PORT` |
|
|
508
|
+
| Video API | `MD_VIDEO_` | Same pattern as audio with `MD_VIDEO_*` (defaults: larger upload/sync caps, port **8012**) |
|
|
509
|
+
| YouTube API | `MD_YOUTUBE_` | `MD_YOUTUBE_JOB_TTL_SECONDS`, `MD_YOUTUBE_TEMP_DIR`, `MD_YOUTUBE_CORS_ORIGINS`, `MD_YOUTUBE_API_HOST`, `MD_YOUTUBE_API_PORT` (default **8013**); optional `MD_YOUTUBE_YTDLP` path for audio fallback |
|
|
365
510
|
|
|
366
511
|
Exact variable names match the `ApiSettings` / helper functions in each `api/settings` or `api/app` module.
|
|
367
512
|
|
|
@@ -385,6 +530,10 @@ Two usage patterns:
|
|
|
385
530
|
| PPTX | `python -m md_generator.ppt.api.mcp_server` (see module docstring for flags) |
|
|
386
531
|
| Image | `python -m md_generator.image.api.mcp_server` (see module for CLI) |
|
|
387
532
|
| URL / HTML | `python -m md_generator.url.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
|
|
533
|
+
| Playwright / SPA | `md-playwright-mcp` or `python -m md_generator.playwright.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
|
|
534
|
+
| Audio | `md-audio-mcp` or `python -m md_generator.media.audio.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
|
|
535
|
+
| Video | `md-video-mcp` or `python -m md_generator.media.video.api.mcp_server` — same transports |
|
|
536
|
+
| YouTube | `md-youtube-mcp` or `python -m md_generator.media.youtube.api.mcp_server` — same transports |
|
|
388
537
|
|
|
389
538
|
**Word** and **XLSX** also ship a small runner script in the repo:
|
|
390
539
|
|
|
@@ -419,7 +568,7 @@ Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/test
|
|
|
419
568
|
|------|------|
|
|
420
569
|
| `LICENSE` | MIT license text |
|
|
421
570
|
| `CODE_OF_CONDUCT.md` | [Contributor Covenant](https://www.contributor-covenant.org/) 2.1 |
|
|
422
|
-
| `src/md_generator/` | **Library source** (all formats + `api` subpackages) |
|
|
571
|
+
| `src/md_generator/` | **Library source** (all formats + `api` subpackages); **audio/video** under [`media/audio/`](src/md_generator/media/audio/) and [`media/video/`](src/md_generator/media/video/) |
|
|
423
572
|
| `pyproject.toml` | Packaging, extras, CLI entry points, pytest |
|
|
424
573
|
| `*-to-md/` | **Docs, tests, fixtures**, thin `converter.py` shims, some `run.py` helpers |
|
|
425
574
|
| `README.md` | This document |
|
|
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mdengine"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "Convert PDF, Office, images, text/JSON/XML, ZIP archives, and web URLs to Markdown."
|
|
7
|
+
version = "0.4.0"
|
|
8
|
+
description = "Convert PDF, Office, images, audio, video, text/JSON/XML, ZIP archives, and web URLs to Markdown."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
license = "MIT"
|
|
12
12
|
license-files = ["LICENSE"]
|
|
13
13
|
authors = [{ name = "mdengine contributors" }]
|
|
14
|
-
keywords = ["markdown", "pdf", "docx", "pptx", "xlsx", "ocr", "zip", "url", "html"]
|
|
14
|
+
keywords = ["markdown", "pdf", "docx", "pptx", "xlsx", "ocr", "zip", "url", "html", "youtube", "playwright"]
|
|
15
15
|
classifiers = [
|
|
16
16
|
"Programming Language :: Python :: 3",
|
|
17
17
|
"Programming Language :: Python :: 3 :: Only",
|
|
@@ -72,6 +72,26 @@ url-full = [
|
|
|
72
72
|
"openpyxl>=3.1.0",
|
|
73
73
|
"pytesseract>=0.3.10",
|
|
74
74
|
]
|
|
75
|
+
# Whisper + PyTorch; metadata uses ffprobe when available, else ``ffmpeg -i`` (see imageio-ffmpeg).
|
|
76
|
+
audio = ["openai-whisper>=20231117", "imageio-ffmpeg>=0.5.1"]
|
|
77
|
+
# Same ML stack as audio; ships a bundled ``ffmpeg`` binary when the system has none.
|
|
78
|
+
video = ["openai-whisper>=20231117", "imageio-ffmpeg>=0.5.1"]
|
|
79
|
+
youtube = [
|
|
80
|
+
"youtube-transcript-api>=0.6.0",
|
|
81
|
+
"httpx>=0.27.0",
|
|
82
|
+
"beautifulsoup4>=4.12.0",
|
|
83
|
+
"lxml>=5.0.0",
|
|
84
|
+
]
|
|
85
|
+
# Playwright-rendered SPA → Markdown (install browsers: playwright install chromium).
|
|
86
|
+
playwright = [
|
|
87
|
+
"playwright>=1.49.0",
|
|
88
|
+
"httpx>=0.27.0",
|
|
89
|
+
"beautifulsoup4>=4.12.0",
|
|
90
|
+
"lxml>=5.0.0",
|
|
91
|
+
"markdownify>=0.14.0",
|
|
92
|
+
"readability-lxml>=0.8.1",
|
|
93
|
+
"Pillow>=10.0.0",
|
|
94
|
+
]
|
|
75
95
|
api = [
|
|
76
96
|
"fastapi>=0.115.0",
|
|
77
97
|
"uvicorn[standard]>=0.32.0",
|
|
@@ -83,9 +103,13 @@ mcp = ["mcp>=1.2.0", "fastmcp>=2.3.0"]
|
|
|
83
103
|
dev = [
|
|
84
104
|
"pytest>=8.0.0",
|
|
85
105
|
"httpx>=0.27.0",
|
|
106
|
+
"beautifulsoup4>=4.12.0",
|
|
107
|
+
"lxml>=5.0.0",
|
|
108
|
+
"youtube-transcript-api>=0.6.0",
|
|
86
109
|
"mdengine[api]",
|
|
87
110
|
"mdengine[mcp]",
|
|
88
111
|
"mdengine[url]",
|
|
112
|
+
"mdengine[playwright]",
|
|
89
113
|
]
|
|
90
114
|
all = [
|
|
91
115
|
"pymupdf>=1.24.0",
|
|
@@ -112,6 +136,7 @@ all = [
|
|
|
112
136
|
"beautifulsoup4>=4.12.0",
|
|
113
137
|
"lxml_html_clean>=0.4.0",
|
|
114
138
|
"readability-lxml>=0.8.1",
|
|
139
|
+
"youtube-transcript-api>=0.6.0",
|
|
115
140
|
]
|
|
116
141
|
|
|
117
142
|
[project.urls]
|
|
@@ -128,6 +153,18 @@ md-image = "md_generator.image.converter:main"
|
|
|
128
153
|
md-text = "md_generator.text.converter:main"
|
|
129
154
|
md-zip = "md_generator.archive.converter:main"
|
|
130
155
|
md-url = "md_generator.url.converter:main"
|
|
156
|
+
md-audio = "md_generator.media.audio.converter:main"
|
|
157
|
+
md-video = "md_generator.media.video.converter:main"
|
|
158
|
+
md-audio-api = "md_generator.media.audio.api.run:main"
|
|
159
|
+
md-video-api = "md_generator.media.video.api.run:main"
|
|
160
|
+
md-audio-mcp = "md_generator.media.audio.api.mcp_server:main"
|
|
161
|
+
md-video-mcp = "md_generator.media.video.api.mcp_server:main"
|
|
162
|
+
md-youtube = "md_generator.media.youtube.converter:main"
|
|
163
|
+
md-youtube-api = "md_generator.media.youtube.api.run:main"
|
|
164
|
+
md-youtube-mcp = "md_generator.media.youtube.api.mcp_server:main"
|
|
165
|
+
md-playwright = "md_generator.playwright.cli:main"
|
|
166
|
+
md-playwright-api = "md_generator.playwright.api.run:main"
|
|
167
|
+
md-playwright-mcp = "md_generator.playwright.api.mcp_server:main"
|
|
131
168
|
|
|
132
169
|
[tool.setuptools.packages.find]
|
|
133
170
|
where = ["src"]
|
|
@@ -143,5 +180,9 @@ testpaths = [
|
|
|
143
180
|
"txt-json-xml-to-md/tests",
|
|
144
181
|
"zip-to-md/tests",
|
|
145
182
|
"url-to-md/tests",
|
|
183
|
+
"audio-to-md/tests",
|
|
184
|
+
"video-to-md/tests",
|
|
185
|
+
"youtube-to-md/tests",
|
|
186
|
+
"playwright-to-md/tests",
|
|
146
187
|
]
|
|
147
188
|
markers = ["integration: optional dependency or slower checks"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Media helpers: document probing (ffprobe/ffmpeg) and audio/video to Markdown."""
|
|
2
|
+
|
|
3
|
+
from md_generator.media.document_converter import (
|
|
4
|
+
DocumentConverter,
|
|
5
|
+
MediaToolsError,
|
|
6
|
+
VideoProbeResult,
|
|
7
|
+
ffprobe_json,
|
|
8
|
+
require_ffmpeg_tools,
|
|
9
|
+
resolve_ffmpeg_executable,
|
|
10
|
+
video_probe_from_ffprobe,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"DocumentConverter",
|
|
15
|
+
"MediaToolsError",
|
|
16
|
+
"VideoProbeResult",
|
|
17
|
+
"ffprobe_json",
|
|
18
|
+
"require_ffmpeg_tools",
|
|
19
|
+
"resolve_ffmpeg_executable",
|
|
20
|
+
"video_probe_from_ffprobe",
|
|
21
|
+
]
|