mdengine 0.3.0__tar.gz → 0.5.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.
Files changed (249) hide show
  1. {mdengine-0.3.0 → mdengine-0.5.0}/PKG-INFO +98 -11
  2. {mdengine-0.3.0 → mdengine-0.5.0}/README.md +64 -9
  3. {mdengine-0.3.0 → mdengine-0.5.0}/pyproject.toml +60 -2
  4. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/__init__.py +1 -1
  5. mdengine-0.5.0/src/md_generator/db/__init__.py +5 -0
  6. mdengine-0.5.0/src/md_generator/db/adapters/__init__.py +3 -0
  7. mdengine-0.5.0/src/md_generator/db/adapters/factory.py +40 -0
  8. mdengine-0.5.0/src/md_generator/db/adapters/mongo_adapter.py +142 -0
  9. mdengine-0.5.0/src/md_generator/db/adapters/mysql_adapter.py +310 -0
  10. mdengine-0.5.0/src/md_generator/db/adapters/oracle_adapter.py +330 -0
  11. mdengine-0.5.0/src/md_generator/db/adapters/postgres_adapter.py +290 -0
  12. mdengine-0.5.0/src/md_generator/db/adapters/sql_common.py +102 -0
  13. mdengine-0.5.0/src/md_generator/db/api/__init__.py +3 -0
  14. mdengine-0.5.0/src/md_generator/db/api/main.py +178 -0
  15. mdengine-0.5.0/src/md_generator/db/api/mcp_server.py +29 -0
  16. mdengine-0.5.0/src/md_generator/db/api/run.py +15 -0
  17. mdengine-0.5.0/src/md_generator/db/api/schemas.py +82 -0
  18. mdengine-0.5.0/src/md_generator/db/api/settings.py +31 -0
  19. mdengine-0.5.0/src/md_generator/db/cli/__init__.py +1 -0
  20. mdengine-0.5.0/src/md_generator/db/cli/main.py +162 -0
  21. mdengine-0.5.0/src/md_generator/db/config/__init__.py +1 -0
  22. mdengine-0.5.0/src/md_generator/db/config/default.yaml +37 -0
  23. mdengine-0.5.0/src/md_generator/db/core/__init__.py +3 -0
  24. mdengine-0.5.0/src/md_generator/db/core/base_adapter.py +73 -0
  25. mdengine-0.5.0/src/md_generator/db/core/erd/__init__.py +3 -0
  26. mdengine-0.5.0/src/md_generator/db/core/erd/dot_emitter.py +50 -0
  27. mdengine-0.5.0/src/md_generator/db/core/erd/filter.py +65 -0
  28. mdengine-0.5.0/src/md_generator/db/core/erd/mermaid_emitter.py +39 -0
  29. mdengine-0.5.0/src/md_generator/db/core/erd/mermaid_render.py +27 -0
  30. mdengine-0.5.0/src/md_generator/db/core/erd/model.py +65 -0
  31. mdengine-0.5.0/src/md_generator/db/core/erd/pipeline.py +199 -0
  32. mdengine-0.5.0/src/md_generator/db/core/erd/render.py +35 -0
  33. mdengine-0.5.0/src/md_generator/db/core/extractor.py +537 -0
  34. mdengine-0.5.0/src/md_generator/db/core/job_manager.py +287 -0
  35. mdengine-0.5.0/src/md_generator/db/core/markdown_writer.py +429 -0
  36. mdengine-0.5.0/src/md_generator/db/core/models.py +163 -0
  37. mdengine-0.5.0/src/md_generator/db/core/run_config.py +140 -0
  38. mdengine-0.5.0/src/md_generator/db/core/util.py +22 -0
  39. mdengine-0.5.0/src/md_generator/db/core/zip_export.py +25 -0
  40. mdengine-0.5.0/src/md_generator/db/mcp/__init__.py +1 -0
  41. mdengine-0.5.0/src/md_generator/db/mcp/server.py +62 -0
  42. mdengine-0.5.0/src/md_generator/db/mcp/sse.py +9 -0
  43. mdengine-0.5.0/src/md_generator/db/mcp/stream.py +18 -0
  44. mdengine-0.5.0/src/md_generator/engine_cli.py +30 -0
  45. mdengine-0.5.0/src/md_generator/graph/__init__.py +3 -0
  46. mdengine-0.5.0/src/md_generator/graph/adapters/__init__.py +3 -0
  47. mdengine-0.5.0/src/md_generator/graph/adapters/factory.py +16 -0
  48. mdengine-0.5.0/src/md_generator/graph/adapters/neo4j_adapter.py +310 -0
  49. mdengine-0.5.0/src/md_generator/graph/adapters/networkx_adapter.py +105 -0
  50. mdengine-0.5.0/src/md_generator/graph/api/__init__.py +1 -0
  51. mdengine-0.5.0/src/md_generator/graph/api/main.py +181 -0
  52. mdengine-0.5.0/src/md_generator/graph/api/mcp_server.py +29 -0
  53. mdengine-0.5.0/src/md_generator/graph/api/run.py +15 -0
  54. mdengine-0.5.0/src/md_generator/graph/api/schemas.py +70 -0
  55. mdengine-0.5.0/src/md_generator/graph/api/settings.py +31 -0
  56. mdengine-0.5.0/src/md_generator/graph/cli/__init__.py +1 -0
  57. mdengine-0.5.0/src/md_generator/graph/cli/main.py +138 -0
  58. mdengine-0.5.0/src/md_generator/graph/config/__init__.py +1 -0
  59. mdengine-0.5.0/src/md_generator/graph/config/default.yaml +30 -0
  60. mdengine-0.5.0/src/md_generator/graph/core/__init__.py +3 -0
  61. mdengine-0.5.0/src/md_generator/graph/core/base_adapter.py +35 -0
  62. mdengine-0.5.0/src/md_generator/graph/core/extractor.py +93 -0
  63. mdengine-0.5.0/src/md_generator/graph/core/graph_builder.py +72 -0
  64. mdengine-0.5.0/src/md_generator/graph/core/job_manager.py +280 -0
  65. mdengine-0.5.0/src/md_generator/graph/core/markdown_writer.py +280 -0
  66. mdengine-0.5.0/src/md_generator/graph/core/models.py +37 -0
  67. mdengine-0.5.0/src/md_generator/graph/core/run_config.py +174 -0
  68. mdengine-0.5.0/src/md_generator/graph/core/viz.py +119 -0
  69. mdengine-0.5.0/src/md_generator/graph/core/zip_export.py +24 -0
  70. mdengine-0.5.0/src/md_generator/graph/mcp/__init__.py +1 -0
  71. mdengine-0.5.0/src/md_generator/graph/mcp/server.py +118 -0
  72. mdengine-0.5.0/src/md_generator/graph/mcp/sse.py +8 -0
  73. mdengine-0.5.0/src/md_generator/graph/mcp/stream.py +5 -0
  74. mdengine-0.5.0/src/md_generator/media/youtube/__init__.py +34 -0
  75. mdengine-0.5.0/src/md_generator/media/youtube/api/__init__.py +1 -0
  76. mdengine-0.5.0/src/md_generator/media/youtube/api/main.py +140 -0
  77. mdengine-0.5.0/src/md_generator/media/youtube/api/mcp_server.py +31 -0
  78. mdengine-0.5.0/src/md_generator/media/youtube/api/mcp_setup.py +48 -0
  79. mdengine-0.5.0/src/md_generator/media/youtube/api/run.py +30 -0
  80. mdengine-0.5.0/src/md_generator/media/youtube/api/settings.py +24 -0
  81. mdengine-0.5.0/src/md_generator/media/youtube/converter.py +140 -0
  82. mdengine-0.5.0/src/md_generator/media/youtube/formatter.py +58 -0
  83. mdengine-0.5.0/src/md_generator/media/youtube/metadata.py +210 -0
  84. mdengine-0.5.0/src/md_generator/media/youtube/service.py +200 -0
  85. mdengine-0.5.0/src/md_generator/media/youtube/transcript.py +100 -0
  86. mdengine-0.5.0/src/md_generator/playwright/__init__.py +6 -0
  87. mdengine-0.5.0/src/md_generator/playwright/api/__init__.py +1 -0
  88. mdengine-0.5.0/src/md_generator/playwright/api/convert_runner.py +71 -0
  89. mdengine-0.5.0/src/md_generator/playwright/api/jobs.py +92 -0
  90. mdengine-0.5.0/src/md_generator/playwright/api/main.py +295 -0
  91. mdengine-0.5.0/src/md_generator/playwright/api/mcp_server.py +37 -0
  92. mdengine-0.5.0/src/md_generator/playwright/api/mcp_setup.py +58 -0
  93. mdengine-0.5.0/src/md_generator/playwright/api/run.py +29 -0
  94. mdengine-0.5.0/src/md_generator/playwright/api/settings.py +26 -0
  95. mdengine-0.5.0/src/md_generator/playwright/assets.py +119 -0
  96. mdengine-0.5.0/src/md_generator/playwright/chunker.py +53 -0
  97. mdengine-0.5.0/src/md_generator/playwright/cli.py +131 -0
  98. mdengine-0.5.0/src/md_generator/playwright/extractor.py +24 -0
  99. mdengine-0.5.0/src/md_generator/playwright/html_to_md.py +25 -0
  100. mdengine-0.5.0/src/md_generator/playwright/options.py +35 -0
  101. mdengine-0.5.0/src/md_generator/playwright/pipeline.py +65 -0
  102. mdengine-0.5.0/src/md_generator/playwright/playwright_fetcher.py +107 -0
  103. {mdengine-0.3.0 → mdengine-0.5.0}/src/mdengine.egg-info/PKG-INFO +98 -11
  104. {mdengine-0.3.0 → mdengine-0.5.0}/src/mdengine.egg-info/SOURCES.txt +98 -0
  105. {mdengine-0.3.0 → mdengine-0.5.0}/src/mdengine.egg-info/entry_points.txt +13 -0
  106. {mdengine-0.3.0 → mdengine-0.5.0}/src/mdengine.egg-info/requires.txt +36 -0
  107. {mdengine-0.3.0 → mdengine-0.5.0}/LICENSE +0 -0
  108. {mdengine-0.3.0 → mdengine-0.5.0}/setup.cfg +0 -0
  109. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/__init__.py +0 -0
  110. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/api/__init__.py +0 -0
  111. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/api/convert_runner.py +0 -0
  112. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/api/jobs.py +0 -0
  113. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/api/main.py +0 -0
  114. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/api/mcp_server.py +0 -0
  115. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/api/mcp_setup.py +0 -0
  116. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/api/query_options.py +0 -0
  117. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/api/settings.py +0 -0
  118. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/convert_impl.py +0 -0
  119. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/converter.py +0 -0
  120. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/archive/options.py +0 -0
  121. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/__init__.py +0 -0
  122. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/api/__init__.py +0 -0
  123. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/api/main.py +0 -0
  124. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/api/mcp_server.py +0 -0
  125. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/api/query_options.py +0 -0
  126. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/api/settings.py +0 -0
  127. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/api/staging.py +0 -0
  128. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/api/zip_bundle.py +0 -0
  129. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/backends/__init__.py +0 -0
  130. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/backends/base.py +0 -0
  131. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/backends/easy.py +0 -0
  132. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/backends/paddle.py +0 -0
  133. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/backends/tesseract.py +0 -0
  134. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/convert_impl.py +0 -0
  135. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/converter.py +0 -0
  136. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/emit.py +0 -0
  137. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/io_util.py +0 -0
  138. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/image/utils.py +0 -0
  139. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/__init__.py +0 -0
  140. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/__init__.py +0 -0
  141. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/api/__init__.py +0 -0
  142. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/api/main.py +0 -0
  143. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/api/mcp_server.py +0 -0
  144. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/api/mcp_setup.py +0 -0
  145. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/api/run.py +0 -0
  146. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/api/settings.py +0 -0
  147. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/converter.py +0 -0
  148. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/formatter.py +0 -0
  149. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/audio/service.py +0 -0
  150. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/document_converter.py +0 -0
  151. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/job_store.py +0 -0
  152. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/__init__.py +0 -0
  153. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/api/__init__.py +0 -0
  154. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/api/main.py +0 -0
  155. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/api/mcp_server.py +0 -0
  156. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/api/mcp_setup.py +0 -0
  157. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/api/run.py +0 -0
  158. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/api/settings.py +0 -0
  159. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/converter.py +0 -0
  160. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/formatter.py +0 -0
  161. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/video/service.py +0 -0
  162. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/media/whisper_language.py +0 -0
  163. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/__init__.py +0 -0
  164. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/api/__init__.py +0 -0
  165. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/api/main.py +0 -0
  166. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/api/mcp_server.py +0 -0
  167. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/api/settings.py +0 -0
  168. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/api/zip_bundle.py +0 -0
  169. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/converter.py +0 -0
  170. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/md_emit.py +0 -0
  171. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/pdf_extract.py +0 -0
  172. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/pdf/utils.py +0 -0
  173. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/__init__.py +0 -0
  174. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/api/__init__.py +0 -0
  175. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/api/convert_runner.py +0 -0
  176. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/api/jobs.py +0 -0
  177. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/api/main.py +0 -0
  178. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/api/mcp_server.py +0 -0
  179. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/api/mcp_setup.py +0 -0
  180. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/api/query_options.py +0 -0
  181. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/api/settings.py +0 -0
  182. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/convert_impl.py +0 -0
  183. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/converter.py +0 -0
  184. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/embedded_extract.py +0 -0
  185. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/ooxml_media.py +0 -0
  186. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/options.py +0 -0
  187. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/post_assets.py +0 -0
  188. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/text_formatting.py +0 -0
  189. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/vendor_pdf_md/__init__.py +0 -0
  190. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/vendor_pdf_md/convert.py +0 -0
  191. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/vendor_word_md/__init__.py +0 -0
  192. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/vendor_word_md/convert.py +0 -0
  193. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/ppt/zip_deep.py +0 -0
  194. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/__init__.py +0 -0
  195. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/api/__init__.py +0 -0
  196. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/api/convert_runner.py +0 -0
  197. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/api/jobs.py +0 -0
  198. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/api/main.py +0 -0
  199. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/api/mcp_server.py +0 -0
  200. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/api/mcp_setup.py +0 -0
  201. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/api/query_options.py +0 -0
  202. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/api/settings.py +0 -0
  203. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/convert_impl.py +0 -0
  204. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/converter.py +0 -0
  205. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/format_detect.py +0 -0
  206. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/md_emit_json.py +0 -0
  207. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/md_emit_txt.py +0 -0
  208. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/md_emit_xml.py +0 -0
  209. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/text/options.py +0 -0
  210. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/__init__.py +0 -0
  211. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/api/__init__.py +0 -0
  212. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/api/convert_runner.py +0 -0
  213. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/api/jobs.py +0 -0
  214. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/api/main.py +0 -0
  215. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/api/mcp_server.py +0 -0
  216. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/api/mcp_setup.py +0 -0
  217. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/api/query_options.py +0 -0
  218. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/api/settings.py +0 -0
  219. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/assets.py +0 -0
  220. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/convert_impl.py +0 -0
  221. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/converter.py +0 -0
  222. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/crawl.py +0 -0
  223. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/extract.py +0 -0
  224. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/fetch.py +0 -0
  225. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/html_to_md.py +0 -0
  226. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/options.py +0 -0
  227. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/page_convert.py +0 -0
  228. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/post_convert_assets.py +0 -0
  229. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/url/robots_util.py +0 -0
  230. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/__init__.py +0 -0
  231. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/api/__init__.py +0 -0
  232. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/api/convert_util.py +0 -0
  233. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/api/jobs.py +0 -0
  234. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/api/main.py +0 -0
  235. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/api/mcp_server.py +0 -0
  236. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/artifact.py +0 -0
  237. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/converter.py +0 -0
  238. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/word/settings.py +0 -0
  239. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/__init__.py +0 -0
  240. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/api/__init__.py +0 -0
  241. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/api/app.py +0 -0
  242. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/convert_config.py +0 -0
  243. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/converter.py +0 -0
  244. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/converter_core.py +0 -0
  245. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/excel_reader.py +0 -0
  246. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/markdown_emitter.py +0 -0
  247. {mdengine-0.3.0 → mdengine-0.5.0}/src/md_generator/xlsx/mcp_server.py +0 -0
  248. {mdengine-0.3.0 → mdengine-0.5.0}/src/mdengine.egg-info/dependency_links.txt +0 -0
  249. {mdengine-0.3.0 → mdengine-0.5.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.3.0
3
+ Version: 0.5.0
4
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,database
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3 :: Only
13
13
  Classifier: Topic :: Text Processing :: Markup :: Markdown
@@ -74,6 +74,31 @@ Requires-Dist: imageio-ffmpeg>=0.5.1; extra == "audio"
74
74
  Provides-Extra: video
75
75
  Requires-Dist: openai-whisper>=20231117; extra == "video"
76
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"
90
+ Provides-Extra: db
91
+ Requires-Dist: sqlalchemy>=2.0.0; extra == "db"
92
+ Requires-Dist: pyyaml>=6.0.0; extra == "db"
93
+ Requires-Dist: psycopg2-binary>=2.9.9; extra == "db"
94
+ Requires-Dist: pymysql>=1.1.0; extra == "db"
95
+ Requires-Dist: oracledb>=2.0.0; extra == "db"
96
+ Requires-Dist: pymongo>=4.6.0; extra == "db"
97
+ Requires-Dist: mermaid-py>=0.8.0; extra == "db"
98
+ Provides-Extra: graph
99
+ Requires-Dist: networkx>=3.2.0; extra == "graph"
100
+ Requires-Dist: neo4j>=5.14.0; extra == "graph"
101
+ Requires-Dist: pyyaml>=6.0.0; extra == "graph"
77
102
  Provides-Extra: api
78
103
  Requires-Dist: fastapi>=0.115.0; extra == "api"
79
104
  Requires-Dist: uvicorn[standard]>=0.32.0; extra == "api"
@@ -86,9 +111,15 @@ Requires-Dist: fastmcp>=2.3.0; extra == "mcp"
86
111
  Provides-Extra: dev
87
112
  Requires-Dist: pytest>=8.0.0; extra == "dev"
88
113
  Requires-Dist: httpx>=0.27.0; extra == "dev"
114
+ Requires-Dist: beautifulsoup4>=4.12.0; extra == "dev"
115
+ Requires-Dist: lxml>=5.0.0; extra == "dev"
116
+ Requires-Dist: youtube-transcript-api>=0.6.0; extra == "dev"
89
117
  Requires-Dist: mdengine[api]; extra == "dev"
90
118
  Requires-Dist: mdengine[mcp]; extra == "dev"
91
119
  Requires-Dist: mdengine[url]; extra == "dev"
120
+ Requires-Dist: mdengine[playwright]; extra == "dev"
121
+ Requires-Dist: mdengine[db]; extra == "dev"
122
+ Requires-Dist: mdengine[graph]; extra == "dev"
92
123
  Provides-Extra: all
93
124
  Requires-Dist: pymupdf>=1.24.0; extra == "all"
94
125
  Requires-Dist: pdfplumber>=0.11.0; extra == "all"
@@ -114,11 +145,12 @@ Requires-Dist: fastmcp>=2.3.0; extra == "all"
114
145
  Requires-Dist: beautifulsoup4>=4.12.0; extra == "all"
115
146
  Requires-Dist: lxml_html_clean>=0.4.0; extra == "all"
116
147
  Requires-Dist: readability-lxml>=0.8.1; extra == "all"
148
+ Requires-Dist: youtube-transcript-api>=0.6.0; extra == "all"
117
149
  Dynamic: license-file
118
150
 
119
151
  # mdengine
120
152
 
121
- 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.
153
+ Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**, **ZIP archives**, **audio / video** (Whisper transcription → Markdown), **database metadata** (SQL + Mongo), and **graphs** (Neo4j / NetworkX → Markdown) into **Markdown** (and related assets). Install only the extras you need; everything imports under the **`md_generator`** package.
122
154
 
123
155
  - **PyPI name:** `mdengine` (import package: `md_generator`)
124
156
  - **Source:** [github.com/vishal7090/md-generator](https://github.com/vishal7090/md-generator)
@@ -196,6 +228,7 @@ pip install "mdengine[all]"
196
228
  | `video` | **Video → Markdown** (ffmpeg extracts mono 16 kHz WAV, then same Whisper stack as `audio`) |
197
229
  | `api` | FastAPI, uvicorn, httpx, pydantic-settings |
198
230
  | `mcp` | MCP servers (`mcp`, `fastmcp` where used) |
231
+ | `graph` | **Graph → Markdown** (Neo4j Bolt + NetworkX GraphML/GML): `networkx`, `neo4j`, `pyyaml` |
199
232
  | `dev` | pytest + API/MCP test helpers |
200
233
  | `all` | Large superset of dependencies (use only if you need everything) |
201
234
 
@@ -210,7 +243,7 @@ All converters can be run from a terminal after you install the package (with th
210
243
  ### 1. Install (once)
211
244
 
212
245
  ```bash
213
- pip install "mdengine[pdf,word]" # adjust extras: ppt, xlsx, image, archive, text, …
246
+ pip install "mdengine[pdf,word]" # adjust extras: ppt, xlsx, image, archive, text, db, graph, …
214
247
  # or from a clone:
215
248
  pip install -e ".[pdf,word,archive]"
216
249
  ```
@@ -238,10 +271,26 @@ If the shell reports “command not found”, ensure the Python **Scripts** dire
238
271
  | `md-url` | `md_generator.url.converter:main` | `md-url https://example.com/doc ./web-out --artifact-layout` |
239
272
  | `md-audio` | `md_generator.media.audio.converter:main` | `md-audio clip.mp3 transcript.md --model base` |
240
273
  | `md-video` | `md_generator.media.video.converter:main` | `md-video clip.mp4 transcript.md --model base` |
274
+ | `md-youtube` | `md_generator.media.youtube.converter:main` | `md-youtube "https://youtu.be/…" out.md --transcript-lang en` |
241
275
  | `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)) |
242
276
  | `md-video-api` | `md_generator.media.video.api.run:main` | REST + MCP on port **8012** |
277
+ | `md-youtube-api` | `md_generator.media.youtube.api.run:main` | REST + MCP on port **8013** (JSON `url` body; see same section) |
243
278
  | `md-audio-mcp` | `md_generator.media.audio.api.mcp_server:main` | Standalone MCP (`--transport stdio` \| `sse` \| `streamable-http`) |
244
279
  | `md-video-mcp` | `md_generator.media.video.api.mcp_server:main` | Same for video |
280
+ | `md-youtube-mcp` | `md_generator.media.youtube.api.mcp_server:main` | Same for YouTube (`youtube_url_to_markdown`) |
281
+ | `md-db` | `md_generator.db.cli.main:main` | `pip install "mdengine[db]"` then `md-db --config db.yaml` (or `mdengine db-to-md …`) |
282
+ | `md-db-api` | `md_generator.db.api.run:main` | FastAPI on port **8010** (`DB_TO_MD_PORT`): `POST /db-to-md/run`, `/db-to-md/job`, SSE `/db-to-md/job/{id}/events` |
283
+ | `md-db-mcp` | `md_generator.db.api.mcp_server:main` | Standalone MCP for metadata export tools |
284
+ | `md-graph` | `md_generator.graph.cli.main:main` | `pip install "mdengine[graph]"` then `md-graph --source neo4j --uri bolt://…` (or `mdengine graph-to-md …`) |
285
+ | `md-graph-api` | `md_generator.graph.api.run:main` | FastAPI on port **8012** (`GRAPH_TO_MD_PORT`): `POST /graph-to-md/run`, `/graph-to-md/job`, SSE `/graph-to-md/job/{id}/events` |
286
+ | `md-graph-mcp` | `md_generator.graph.api.mcp_server:main` | Standalone MCP for graph export tools |
287
+ | `mdengine` | `md_generator.engine_cli:main` | `mdengine db-to-md …` / `mdengine graph-to-md …` (delegates to `md-db` / `md-graph`) |
288
+
289
+ **db-to-md ER diagrams:** add **`erd`** to the export feature list (YAML `features.include`, API body, or CLI `--include …,erd`). **Preferred:** **Graphviz** (`dot` on `PATH`, or **`GRAPHVIZ_DOT`**) produces `erd/*.dot`, `erd/*.png`, and `erd/*.svg`. **If Graphviz is missing,** the exporter falls back to **Mermaid** (`erDiagram`): it writes `erd/*.mermaid` plus a fenced **`erd/*.md`** for GitHub-style preview. With **`mermaid-py`** (included in `mdengine[db]`), it also requests **PNG/SVG** via mermaid.ink (requires network unless you self-host mermaid.ink and set **`MERMAID_INK_SERVER`** per [mermaid-py](https://pypi.org/project/mermaid-py/)). Tune **`erd.max_tables`** (default 100) and **`erd.scope`** (`full` \| `per_schema` \| `per_table`) under `erd:` in YAML; CLI: `--erd-max-tables`, `--erd-scope`. Async job SSE uses `progress_update` with `current` starting with `erd:`.
290
+
291
+ **db-to-md split exports and README merge:** with **`output.split_files: true`**, set **`output.write_combined_feature_markdown: true`** to also write root-level combined Markdown (for example `tables.md`, `functions.md`, `indexes.md`, and feature-specific paths such as `oracle/packages.md` or `mongodb/collections.md` when those features run). Set **`output.readme_feature_merge`** to **`inline`** (append full bundle bodies into `README.md`) or **`toc`** (append a linked list to those files). If merge is not **`none`** and split files are on, combined bundle writes are turned on automatically when loading config. CLI: `--write-combined-feature-markdown`, `--readme-feature-merge none|inline|toc`.
292
+
293
+ **graph-to-md (Neo4j + NetworkX):** library lives under [`md_generator/graph/`](src/md_generator/graph/). **Sources:** **`networkx`** (GraphML/GML via `graph.graph_file` or `--graph-file`) or **`neo4j`** (`graph.uri`, `graph.user`, `graph.password`, optional `graph.database` for `session(database=…)`). **Output layout:** by default **`output.combine_markdown: true`** writes **`nodes.md`**, **`relationship.md`**, and **`graph_summary.md`** (summary plus embedded nodes and relationships). Set **`combine_markdown: false`** or CLI **`--individual` / `--markdown-layout individual`** for per-entity files under **`nodes/`** and **`relationships/`**. **Diagrams:** **`viz.mermaid: true`** (default) writes **`graph/graph.mmd`** and embeds a fenced Mermaid block in the export **`README.md`** (no Graphviz required). **`viz.enabled: true`** or CLI **`--viz`** also writes **`graph/graph.dot`** and runs **`dot`** for PNG/SVG/PDF when Graphviz is on `PATH` (or **`GRAPHVIZ_DOT`**). CLI **`--no-mermaid`** disables Mermaid; **`--depth`**, **`--start-node`**, **`--max-nodes`**, **`--max-edges`** bound traversal. Packaged defaults: [`src/md_generator/graph/config/default.yaml`](src/md_generator/graph/config/default.yaml). Tests: **`graph-to-md/tests/`**; API image: [`graph-to-md/Dockerfile.api`](graph-to-md/Dockerfile.api).
245
294
 
246
295
  Every command accepts **`-h` / `--help`** for full flags (artifact layout, OCR, ZIP options, etc.).
247
296
 
@@ -261,6 +310,7 @@ md-zip archive.zip ./unzipped-md
261
310
  md-url https://example.com/page ./page-bundle --artifact-layout
262
311
  md-audio ./voice.mp3 ./voice.md --model tiny
263
312
  md-video ./screen.mp4 ./screen.md --model base
313
+ pip install "mdengine[graph]" && md-graph --source neo4j --uri neo4j://localhost:7687 --user neo4j --password secret --database neo4j --output ./graph-out --viz
264
314
  ```
265
315
 
266
316
  **Windows PowerShell** (same commands; use backslashes for paths if you prefer)
@@ -271,6 +321,8 @@ md-zip .\archive.zip .\zip-out
271
321
  md-url https://example.com/page .\page-bundle --artifact-layout
272
322
  md-audio .\voice.mp3 .\voice.md --model tiny
273
323
  md-video .\screen.mp4 .\screen.md --model base
324
+ pip install "mdengine[graph]"
325
+ md-graph --source neo4j --uri neo4j://localhost:7687 --user neo4j --password secret --database neo4j --output .\graph-out --viz
274
326
  ```
275
327
 
276
328
  **Windows CMD**
@@ -455,6 +507,7 @@ Library code lives under **`md_generator.media`**: shared probing in [`document_
455
507
  ```bash
456
508
  pip install "mdengine[audio,api,mcp]" # audio CLI + HTTP + MCP
457
509
  pip install "mdengine[video,api,mcp]" # video CLI + HTTP + MCP (same ML stack as audio)
510
+ pip install "mdengine[youtube,api,mcp]" # YouTube URL → Markdown (captions + metadata; optional Whisper fallback)
458
511
  ```
459
512
 
460
513
  ### Python library
@@ -483,6 +536,18 @@ md = svc.to_markdown(Path("input.mp4"), title=None)
483
536
  svc.write_markdown(Path("input.mp4"), Path("out/transcript.md"))
484
537
  ```
485
538
 
539
+ **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`):
540
+
541
+ ```python
542
+ from md_generator.media.youtube import YouTubeToMarkdownService
543
+
544
+ svc = YouTubeToMarkdownService(whisper_model="base")
545
+ md = svc.to_markdown("https://www.youtube.com/watch?v=VIDEO_ID", transcript_languages=["en"])
546
+ svc.write_markdown("https://youtu.be/VIDEO_ID", Path("out/youtube.md"))
547
+ ```
548
+
549
+ 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).
550
+
486
551
  Public symbols are also re-exported from [`md_generator.media`](src/md_generator/media/__init__.py) for ffprobe helpers (`ffprobe_json`, `VideoProbeResult`, …).
487
552
 
488
553
  ### REST API (FastAPI)
@@ -497,13 +562,15 @@ Each service exposes the same job pattern as other converters:
497
562
  | `GET /convert/jobs/{job_id}/download` | Markdown when `done`; workspace removed after download. |
498
563
 
499
564
  **Audio** defaults: `MD_AUDIO_MAX_UPLOAD_MB=200`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB=40`, `MD_AUDIO_API_PORT=8011`.
500
- **Video** defaults: `MD_VIDEO_MAX_UPLOAD_MB=500`, `MD_VIDEO_MAX_SYNC_UPLOAD_MB=80`, `MD_VIDEO_API_PORT=8012`.
565
+ **Video** defaults: `MD_VIDEO_MAX_UPLOAD_MB=500`, `MD_VIDEO_MAX_SYNC_UPLOAD_MB=80`, `MD_VIDEO_API_PORT=8012`.
566
+ **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`.
501
567
 
502
568
  Run with the bundled runners (each call builds the app with **`factory=True`** for a clean MCP session manager):
503
569
 
504
570
  ```bash
505
571
  md-audio-api --host 127.0.0.1 --port 8011
506
572
  md-video-api --host 127.0.0.1 --port 8012
573
+ md-youtube-api --host 127.0.0.1 --port 8013
507
574
  ```
508
575
 
509
576
  Or with Uvicorn directly (the ASGI app is built by **`create_app()`** so each worker gets its own MCP session manager):
@@ -511,6 +578,7 @@ Or with Uvicorn directly (the ASGI app is built by **`create_app()`** so each wo
511
578
  ```bash
512
579
  uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
513
580
  uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
581
+ uvicorn md_generator.media.youtube.api.main:create_app --factory --host 127.0.0.1 --port 8013
514
582
  ```
515
583
 
516
584
  The module also defines **`app = create_app()`** for a single-process target: `uvicorn md_generator.media.audio.api.main:app` (no `--factory`).
@@ -519,7 +587,7 @@ Swagger is at **`/docs`** when the app is running.
519
587
 
520
588
  ### MCP (stdio, SSE, streamable HTTP)
521
589
 
522
- 1. **With FastAPI** — start `md-audio-api` or `md-video-api`; mount Streamable HTTP MCP at **`http://<host>:<port>/mcp`** (same host as REST).
590
+ 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).
523
591
  2. **Standalone** — process speaks MCP only:
524
592
 
525
593
  ```bash
@@ -527,16 +595,18 @@ md-audio-mcp --transport stdio
527
595
  md-audio-mcp --transport sse
528
596
  md-audio-mcp --transport streamable-http
529
597
  md-video-mcp --transport stdio
598
+ md-youtube-mcp --transport stdio
530
599
  ```
531
600
 
532
601
  **Audio MCP tools:** `transcribe_audio_path`, `transcribe_audio_base64`.
533
- **Video MCP tools:** `transcribe_video_path`, `transcribe_video_base64`.
602
+ **Video MCP tools:** `transcribe_video_path`, `transcribe_video_base64`.
603
+ **YouTube MCP tool:** `youtube_url_to_markdown`.
534
604
 
535
- Equivalent modules: `python -m md_generator.media.audio.api.mcp_server`, `python -m md_generator.media.video.api.mcp_server`.
605
+ 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`.
536
606
 
537
607
  ### Thin shims (repo clone)
538
608
 
539
- [`audio-to-md/converter.py`](audio-to-md/converter.py) and [`video-to-md/converter.py`](video-to-md/converter.py) delegate to the same `main` as `md-audio` / `md-video`. Tests and `pytest.ini` live under `audio-to-md/tests/` and `video-to-md/tests/`.
609
+ [`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/`. [`db-to-md/converter.py`](db-to-md/converter.py) delegates to `md-db`; tests live under `db-to-md/tests/`. **graph-to-md** uses `md-graph` / `mdengine graph-to-md` directly (no thin `converter.py` shim); tests live under [`graph-to-md/tests/`](graph-to-md/tests/).
540
610
 
541
611
  ---
542
612
 
@@ -565,8 +635,12 @@ Install `mdengine[api]` plus the format extra(s), then run the **`app`** object
565
635
  | Text/JSON/XML | `md_generator.text.api.main:app` | `text`, `api`, `mcp` |
566
636
  | ZIP | `md_generator.archive.api.main:app` | `archive`, `api`, `mcp` (+ extras for nested office/PDF) |
567
637
  | URL / HTML | `md_generator.url.api.main:app` | `url`, `api`, `mcp` |
638
+ | Playwright / SPA | `md_generator.playwright.api.main:app` | `playwright`, `api`, `mcp` |
639
+ | Database metadata | `md_generator.db.api.main:app` | `db`, `api`, `mcp` |
640
+ | Graph metadata (Neo4j / NetworkX) | `md_generator.graph.api.main:app` | `graph`, `api`, `mcp` |
568
641
  | Audio (Whisper) | `md_generator.media.audio.api.main:create_app` (use **`--factory`**) or `…main:app` | `audio`, `api`, `mcp` |
569
642
  | Video (Whisper) | `md_generator.media.video.api.main:create_app` (use **`--factory`**) or `…main:app` | `video`, `api`, `mcp` |
643
+ | YouTube | `md_generator.media.youtube.api.main:create_app` (use **`--factory`**) or `…main:app` | `youtube`, `api`, `mcp` |
570
644
 
571
645
  Examples:
572
646
 
@@ -575,10 +649,15 @@ uvicorn md_generator.pdf.api.main:app --host 127.0.0.1 --port 8001
575
649
  uvicorn md_generator.word.api.main:app --host 127.0.0.1 --port 8002
576
650
  uvicorn md_generator.archive.api.main:app --host 127.0.0.1 --port 8010
577
651
  uvicorn md_generator.url.api.main:app --host 127.0.0.1 --port 8011
652
+ uvicorn md_generator.playwright.api.main:app --host 127.0.0.1 --port 8014
653
+ uvicorn md_generator.graph.api.main:app --host 127.0.0.1 --port 8012
578
654
  uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
579
655
  uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
656
+ uvicorn md_generator.media.youtube.api.main:create_app --factory --host 127.0.0.1 --port 8013
580
657
  ```
581
658
 
659
+ **Port note:** **`md-graph-api`** and **`md-video-api`** both default to **8012**; set **`GRAPH_TO_MD_PORT`** or **`MD_VIDEO_API_PORT`** when you need both on one machine.
660
+
582
661
  ### MCP over HTTP on the same server
583
662
 
584
663
  These apps mount an MCP HTTP app at **`/mcp`** (Streamable HTTP / framework-specific). Start the API as above, then point an MCP client at `http://<host>:<port>/mcp` where supported.
@@ -596,8 +675,12 @@ Prefixes differ per service (often read from a `.env` file next to the process):
596
675
  | Text | `TXT_JSON_XML_TO_MD_` | same pattern |
597
676
  | XLSX | `XLSX_TO_MD_` | `XLSX_TO_MD_TEMP_DIR`, `XLSX_TO_MD_CORS_ORIGINS`, etc. (see `md_generator.xlsx.api.app`) |
598
677
  | 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` |
678
+ | 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**) |
679
+ | Database metadata | `DB_TO_MD_` | `DB_TO_MD_JOB_SQLITE_PATH`, `DB_TO_MD_JOB_WORKSPACE_ROOT`, `DB_TO_MD_CORS_ORIGINS`, `DB_TO_MD_MAX_SYNC_ZIP_MB`, `DB_TO_MD_HOST`, `DB_TO_MD_PORT` (default **8010**) |
680
+ | Graph metadata | `GRAPH_TO_MD_` | `GRAPH_TO_MD_JOB_SQLITE_PATH`, `GRAPH_TO_MD_JOB_WORKSPACE_ROOT`, `GRAPH_TO_MD_CORS_ORIGINS`, `GRAPH_TO_MD_MAX_SYNC_ZIP_MB`, `GRAPH_TO_MD_HOST`, `GRAPH_TO_MD_PORT` (default **8012**) |
599
681
  | 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` |
600
682
  | Video API | `MD_VIDEO_` | Same pattern as audio with `MD_VIDEO_*` (defaults: larger upload/sync caps, port **8012**) |
683
+ | 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 |
601
684
 
602
685
  Exact variable names match the `ApiSettings` / helper functions in each `api/settings` or `api/app` module.
603
686
 
@@ -621,8 +704,12 @@ Two usage patterns:
621
704
  | PPTX | `python -m md_generator.ppt.api.mcp_server` (see module docstring for flags) |
622
705
  | Image | `python -m md_generator.image.api.mcp_server` (see module for CLI) |
623
706
  | URL / HTML | `python -m md_generator.url.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
707
+ | Playwright / SPA | `md-playwright-mcp` or `python -m md_generator.playwright.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
624
708
  | Audio | `md-audio-mcp` or `python -m md_generator.media.audio.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
625
709
  | Video | `md-video-mcp` or `python -m md_generator.media.video.api.mcp_server` — same transports |
710
+ | YouTube | `md-youtube-mcp` or `python -m md_generator.media.youtube.api.mcp_server` — same transports |
711
+ | Database metadata | `md-db-mcp` or `python -m md_generator.db.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
712
+ | Graph (Neo4j / NetworkX) | `md-graph-mcp` or `python -m md_generator.graph.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
626
713
 
627
714
  **Word** and **XLSX** also ship a small runner script in the repo:
628
715
 
@@ -647,7 +734,7 @@ pip install -e ".[dev,all]" # or a smaller subset of extras
647
734
  python -m pytest
648
735
  ```
649
736
 
650
- Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/tests/`); `pyproject.toml` configures `pythonpath = ["src"]` so `md_generator` resolves without a separate `PYTHONPATH`.
737
+ Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/tests/`) and **`graph-to-md/tests/`**; `pyproject.toml` configures `pythonpath = ["src"]` so `md_generator` resolves without a separate `PYTHONPATH`.
651
738
 
652
739
  ---
653
740
 
@@ -657,7 +744,7 @@ Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/test
657
744
  |------|------|
658
745
  | `LICENSE` | MIT license text |
659
746
  | `CODE_OF_CONDUCT.md` | [Contributor Covenant](https://www.contributor-covenant.org/) 2.1 |
660
- | `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/) |
747
+ | `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/); **graph-to-md** under [`graph/`](src/md_generator/graph/) |
661
748
  | `pyproject.toml` | Packaging, extras, CLI entry points, pytest |
662
749
  | `*-to-md/` | **Docs, tests, fixtures**, thin `converter.py` shims, some `run.py` helpers |
663
750
  | `README.md` | This document |
@@ -1,6 +1,6 @@
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**, **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.
3
+ Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**, **ZIP archives**, **audio / video** (Whisper transcription → Markdown), **database metadata** (SQL + Mongo), and **graphs** (Neo4j / NetworkX → 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)
@@ -78,6 +78,7 @@ pip install "mdengine[all]"
78
78
  | `video` | **Video → Markdown** (ffmpeg extracts mono 16 kHz WAV, then same Whisper stack as `audio`) |
79
79
  | `api` | FastAPI, uvicorn, httpx, pydantic-settings |
80
80
  | `mcp` | MCP servers (`mcp`, `fastmcp` where used) |
81
+ | `graph` | **Graph → Markdown** (Neo4j Bolt + NetworkX GraphML/GML): `networkx`, `neo4j`, `pyyaml` |
81
82
  | `dev` | pytest + API/MCP test helpers |
82
83
  | `all` | Large superset of dependencies (use only if you need everything) |
83
84
 
@@ -92,7 +93,7 @@ All converters can be run from a terminal after you install the package (with th
92
93
  ### 1. Install (once)
93
94
 
94
95
  ```bash
95
- pip install "mdengine[pdf,word]" # adjust extras: ppt, xlsx, image, archive, text, …
96
+ pip install "mdengine[pdf,word]" # adjust extras: ppt, xlsx, image, archive, text, db, graph, …
96
97
  # or from a clone:
97
98
  pip install -e ".[pdf,word,archive]"
98
99
  ```
@@ -120,10 +121,26 @@ If the shell reports “command not found”, ensure the Python **Scripts** dire
120
121
  | `md-url` | `md_generator.url.converter:main` | `md-url https://example.com/doc ./web-out --artifact-layout` |
121
122
  | `md-audio` | `md_generator.media.audio.converter:main` | `md-audio clip.mp3 transcript.md --model base` |
122
123
  | `md-video` | `md_generator.media.video.converter:main` | `md-video clip.mp4 transcript.md --model base` |
124
+ | `md-youtube` | `md_generator.media.youtube.converter:main` | `md-youtube "https://youtu.be/…" out.md --transcript-lang en` |
123
125
  | `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)) |
124
126
  | `md-video-api` | `md_generator.media.video.api.run:main` | REST + MCP on port **8012** |
127
+ | `md-youtube-api` | `md_generator.media.youtube.api.run:main` | REST + MCP on port **8013** (JSON `url` body; see same section) |
125
128
  | `md-audio-mcp` | `md_generator.media.audio.api.mcp_server:main` | Standalone MCP (`--transport stdio` \| `sse` \| `streamable-http`) |
126
129
  | `md-video-mcp` | `md_generator.media.video.api.mcp_server:main` | Same for video |
130
+ | `md-youtube-mcp` | `md_generator.media.youtube.api.mcp_server:main` | Same for YouTube (`youtube_url_to_markdown`) |
131
+ | `md-db` | `md_generator.db.cli.main:main` | `pip install "mdengine[db]"` then `md-db --config db.yaml` (or `mdengine db-to-md …`) |
132
+ | `md-db-api` | `md_generator.db.api.run:main` | FastAPI on port **8010** (`DB_TO_MD_PORT`): `POST /db-to-md/run`, `/db-to-md/job`, SSE `/db-to-md/job/{id}/events` |
133
+ | `md-db-mcp` | `md_generator.db.api.mcp_server:main` | Standalone MCP for metadata export tools |
134
+ | `md-graph` | `md_generator.graph.cli.main:main` | `pip install "mdengine[graph]"` then `md-graph --source neo4j --uri bolt://…` (or `mdengine graph-to-md …`) |
135
+ | `md-graph-api` | `md_generator.graph.api.run:main` | FastAPI on port **8012** (`GRAPH_TO_MD_PORT`): `POST /graph-to-md/run`, `/graph-to-md/job`, SSE `/graph-to-md/job/{id}/events` |
136
+ | `md-graph-mcp` | `md_generator.graph.api.mcp_server:main` | Standalone MCP for graph export tools |
137
+ | `mdengine` | `md_generator.engine_cli:main` | `mdengine db-to-md …` / `mdengine graph-to-md …` (delegates to `md-db` / `md-graph`) |
138
+
139
+ **db-to-md ER diagrams:** add **`erd`** to the export feature list (YAML `features.include`, API body, or CLI `--include …,erd`). **Preferred:** **Graphviz** (`dot` on `PATH`, or **`GRAPHVIZ_DOT`**) produces `erd/*.dot`, `erd/*.png`, and `erd/*.svg`. **If Graphviz is missing,** the exporter falls back to **Mermaid** (`erDiagram`): it writes `erd/*.mermaid` plus a fenced **`erd/*.md`** for GitHub-style preview. With **`mermaid-py`** (included in `mdengine[db]`), it also requests **PNG/SVG** via mermaid.ink (requires network unless you self-host mermaid.ink and set **`MERMAID_INK_SERVER`** per [mermaid-py](https://pypi.org/project/mermaid-py/)). Tune **`erd.max_tables`** (default 100) and **`erd.scope`** (`full` \| `per_schema` \| `per_table`) under `erd:` in YAML; CLI: `--erd-max-tables`, `--erd-scope`. Async job SSE uses `progress_update` with `current` starting with `erd:`.
140
+
141
+ **db-to-md split exports and README merge:** with **`output.split_files: true`**, set **`output.write_combined_feature_markdown: true`** to also write root-level combined Markdown (for example `tables.md`, `functions.md`, `indexes.md`, and feature-specific paths such as `oracle/packages.md` or `mongodb/collections.md` when those features run). Set **`output.readme_feature_merge`** to **`inline`** (append full bundle bodies into `README.md`) or **`toc`** (append a linked list to those files). If merge is not **`none`** and split files are on, combined bundle writes are turned on automatically when loading config. CLI: `--write-combined-feature-markdown`, `--readme-feature-merge none|inline|toc`.
142
+
143
+ **graph-to-md (Neo4j + NetworkX):** library lives under [`md_generator/graph/`](src/md_generator/graph/). **Sources:** **`networkx`** (GraphML/GML via `graph.graph_file` or `--graph-file`) or **`neo4j`** (`graph.uri`, `graph.user`, `graph.password`, optional `graph.database` for `session(database=…)`). **Output layout:** by default **`output.combine_markdown: true`** writes **`nodes.md`**, **`relationship.md`**, and **`graph_summary.md`** (summary plus embedded nodes and relationships). Set **`combine_markdown: false`** or CLI **`--individual` / `--markdown-layout individual`** for per-entity files under **`nodes/`** and **`relationships/`**. **Diagrams:** **`viz.mermaid: true`** (default) writes **`graph/graph.mmd`** and embeds a fenced Mermaid block in the export **`README.md`** (no Graphviz required). **`viz.enabled: true`** or CLI **`--viz`** also writes **`graph/graph.dot`** and runs **`dot`** for PNG/SVG/PDF when Graphviz is on `PATH` (or **`GRAPHVIZ_DOT`**). CLI **`--no-mermaid`** disables Mermaid; **`--depth`**, **`--start-node`**, **`--max-nodes`**, **`--max-edges`** bound traversal. Packaged defaults: [`src/md_generator/graph/config/default.yaml`](src/md_generator/graph/config/default.yaml). Tests: **`graph-to-md/tests/`**; API image: [`graph-to-md/Dockerfile.api`](graph-to-md/Dockerfile.api).
127
144
 
128
145
  Every command accepts **`-h` / `--help`** for full flags (artifact layout, OCR, ZIP options, etc.).
129
146
 
@@ -143,6 +160,7 @@ md-zip archive.zip ./unzipped-md
143
160
  md-url https://example.com/page ./page-bundle --artifact-layout
144
161
  md-audio ./voice.mp3 ./voice.md --model tiny
145
162
  md-video ./screen.mp4 ./screen.md --model base
163
+ pip install "mdengine[graph]" && md-graph --source neo4j --uri neo4j://localhost:7687 --user neo4j --password secret --database neo4j --output ./graph-out --viz
146
164
  ```
147
165
 
148
166
  **Windows PowerShell** (same commands; use backslashes for paths if you prefer)
@@ -153,6 +171,8 @@ md-zip .\archive.zip .\zip-out
153
171
  md-url https://example.com/page .\page-bundle --artifact-layout
154
172
  md-audio .\voice.mp3 .\voice.md --model tiny
155
173
  md-video .\screen.mp4 .\screen.md --model base
174
+ pip install "mdengine[graph]"
175
+ md-graph --source neo4j --uri neo4j://localhost:7687 --user neo4j --password secret --database neo4j --output .\graph-out --viz
156
176
  ```
157
177
 
158
178
  **Windows CMD**
@@ -337,6 +357,7 @@ Library code lives under **`md_generator.media`**: shared probing in [`document_
337
357
  ```bash
338
358
  pip install "mdengine[audio,api,mcp]" # audio CLI + HTTP + MCP
339
359
  pip install "mdengine[video,api,mcp]" # video CLI + HTTP + MCP (same ML stack as audio)
360
+ pip install "mdengine[youtube,api,mcp]" # YouTube URL → Markdown (captions + metadata; optional Whisper fallback)
340
361
  ```
341
362
 
342
363
  ### Python library
@@ -365,6 +386,18 @@ md = svc.to_markdown(Path("input.mp4"), title=None)
365
386
  svc.write_markdown(Path("input.mp4"), Path("out/transcript.md"))
366
387
  ```
367
388
 
389
+ **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`):
390
+
391
+ ```python
392
+ from md_generator.media.youtube import YouTubeToMarkdownService
393
+
394
+ svc = YouTubeToMarkdownService(whisper_model="base")
395
+ md = svc.to_markdown("https://www.youtube.com/watch?v=VIDEO_ID", transcript_languages=["en"])
396
+ svc.write_markdown("https://youtu.be/VIDEO_ID", Path("out/youtube.md"))
397
+ ```
398
+
399
+ 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).
400
+
368
401
  Public symbols are also re-exported from [`md_generator.media`](src/md_generator/media/__init__.py) for ffprobe helpers (`ffprobe_json`, `VideoProbeResult`, …).
369
402
 
370
403
  ### REST API (FastAPI)
@@ -379,13 +412,15 @@ Each service exposes the same job pattern as other converters:
379
412
  | `GET /convert/jobs/{job_id}/download` | Markdown when `done`; workspace removed after download. |
380
413
 
381
414
  **Audio** defaults: `MD_AUDIO_MAX_UPLOAD_MB=200`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB=40`, `MD_AUDIO_API_PORT=8011`.
382
- **Video** defaults: `MD_VIDEO_MAX_UPLOAD_MB=500`, `MD_VIDEO_MAX_SYNC_UPLOAD_MB=80`, `MD_VIDEO_API_PORT=8012`.
415
+ **Video** defaults: `MD_VIDEO_MAX_UPLOAD_MB=500`, `MD_VIDEO_MAX_SYNC_UPLOAD_MB=80`, `MD_VIDEO_API_PORT=8012`.
416
+ **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`.
383
417
 
384
418
  Run with the bundled runners (each call builds the app with **`factory=True`** for a clean MCP session manager):
385
419
 
386
420
  ```bash
387
421
  md-audio-api --host 127.0.0.1 --port 8011
388
422
  md-video-api --host 127.0.0.1 --port 8012
423
+ md-youtube-api --host 127.0.0.1 --port 8013
389
424
  ```
390
425
 
391
426
  Or with Uvicorn directly (the ASGI app is built by **`create_app()`** so each worker gets its own MCP session manager):
@@ -393,6 +428,7 @@ Or with Uvicorn directly (the ASGI app is built by **`create_app()`** so each wo
393
428
  ```bash
394
429
  uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
395
430
  uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
431
+ uvicorn md_generator.media.youtube.api.main:create_app --factory --host 127.0.0.1 --port 8013
396
432
  ```
397
433
 
398
434
  The module also defines **`app = create_app()`** for a single-process target: `uvicorn md_generator.media.audio.api.main:app` (no `--factory`).
@@ -401,7 +437,7 @@ Swagger is at **`/docs`** when the app is running.
401
437
 
402
438
  ### MCP (stdio, SSE, streamable HTTP)
403
439
 
404
- 1. **With FastAPI** — start `md-audio-api` or `md-video-api`; mount Streamable HTTP MCP at **`http://<host>:<port>/mcp`** (same host as REST).
440
+ 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).
405
441
  2. **Standalone** — process speaks MCP only:
406
442
 
407
443
  ```bash
@@ -409,16 +445,18 @@ md-audio-mcp --transport stdio
409
445
  md-audio-mcp --transport sse
410
446
  md-audio-mcp --transport streamable-http
411
447
  md-video-mcp --transport stdio
448
+ md-youtube-mcp --transport stdio
412
449
  ```
413
450
 
414
451
  **Audio MCP tools:** `transcribe_audio_path`, `transcribe_audio_base64`.
415
- **Video MCP tools:** `transcribe_video_path`, `transcribe_video_base64`.
452
+ **Video MCP tools:** `transcribe_video_path`, `transcribe_video_base64`.
453
+ **YouTube MCP tool:** `youtube_url_to_markdown`.
416
454
 
417
- Equivalent modules: `python -m md_generator.media.audio.api.mcp_server`, `python -m md_generator.media.video.api.mcp_server`.
455
+ 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`.
418
456
 
419
457
  ### Thin shims (repo clone)
420
458
 
421
- [`audio-to-md/converter.py`](audio-to-md/converter.py) and [`video-to-md/converter.py`](video-to-md/converter.py) delegate to the same `main` as `md-audio` / `md-video`. Tests and `pytest.ini` live under `audio-to-md/tests/` and `video-to-md/tests/`.
459
+ [`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/`. [`db-to-md/converter.py`](db-to-md/converter.py) delegates to `md-db`; tests live under `db-to-md/tests/`. **graph-to-md** uses `md-graph` / `mdengine graph-to-md` directly (no thin `converter.py` shim); tests live under [`graph-to-md/tests/`](graph-to-md/tests/).
422
460
 
423
461
  ---
424
462
 
@@ -447,8 +485,12 @@ Install `mdengine[api]` plus the format extra(s), then run the **`app`** object
447
485
  | Text/JSON/XML | `md_generator.text.api.main:app` | `text`, `api`, `mcp` |
448
486
  | ZIP | `md_generator.archive.api.main:app` | `archive`, `api`, `mcp` (+ extras for nested office/PDF) |
449
487
  | URL / HTML | `md_generator.url.api.main:app` | `url`, `api`, `mcp` |
488
+ | Playwright / SPA | `md_generator.playwright.api.main:app` | `playwright`, `api`, `mcp` |
489
+ | Database metadata | `md_generator.db.api.main:app` | `db`, `api`, `mcp` |
490
+ | Graph metadata (Neo4j / NetworkX) | `md_generator.graph.api.main:app` | `graph`, `api`, `mcp` |
450
491
  | Audio (Whisper) | `md_generator.media.audio.api.main:create_app` (use **`--factory`**) or `…main:app` | `audio`, `api`, `mcp` |
451
492
  | Video (Whisper) | `md_generator.media.video.api.main:create_app` (use **`--factory`**) or `…main:app` | `video`, `api`, `mcp` |
493
+ | YouTube | `md_generator.media.youtube.api.main:create_app` (use **`--factory`**) or `…main:app` | `youtube`, `api`, `mcp` |
452
494
 
453
495
  Examples:
454
496
 
@@ -457,10 +499,15 @@ uvicorn md_generator.pdf.api.main:app --host 127.0.0.1 --port 8001
457
499
  uvicorn md_generator.word.api.main:app --host 127.0.0.1 --port 8002
458
500
  uvicorn md_generator.archive.api.main:app --host 127.0.0.1 --port 8010
459
501
  uvicorn md_generator.url.api.main:app --host 127.0.0.1 --port 8011
502
+ uvicorn md_generator.playwright.api.main:app --host 127.0.0.1 --port 8014
503
+ uvicorn md_generator.graph.api.main:app --host 127.0.0.1 --port 8012
460
504
  uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
461
505
  uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
506
+ uvicorn md_generator.media.youtube.api.main:create_app --factory --host 127.0.0.1 --port 8013
462
507
  ```
463
508
 
509
+ **Port note:** **`md-graph-api`** and **`md-video-api`** both default to **8012**; set **`GRAPH_TO_MD_PORT`** or **`MD_VIDEO_API_PORT`** when you need both on one machine.
510
+
464
511
  ### MCP over HTTP on the same server
465
512
 
466
513
  These apps mount an MCP HTTP app at **`/mcp`** (Streamable HTTP / framework-specific). Start the API as above, then point an MCP client at `http://<host>:<port>/mcp` where supported.
@@ -478,8 +525,12 @@ Prefixes differ per service (often read from a `.env` file next to the process):
478
525
  | Text | `TXT_JSON_XML_TO_MD_` | same pattern |
479
526
  | XLSX | `XLSX_TO_MD_` | `XLSX_TO_MD_TEMP_DIR`, `XLSX_TO_MD_CORS_ORIGINS`, etc. (see `md_generator.xlsx.api.app`) |
480
527
  | 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` |
528
+ | 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**) |
529
+ | Database metadata | `DB_TO_MD_` | `DB_TO_MD_JOB_SQLITE_PATH`, `DB_TO_MD_JOB_WORKSPACE_ROOT`, `DB_TO_MD_CORS_ORIGINS`, `DB_TO_MD_MAX_SYNC_ZIP_MB`, `DB_TO_MD_HOST`, `DB_TO_MD_PORT` (default **8010**) |
530
+ | Graph metadata | `GRAPH_TO_MD_` | `GRAPH_TO_MD_JOB_SQLITE_PATH`, `GRAPH_TO_MD_JOB_WORKSPACE_ROOT`, `GRAPH_TO_MD_CORS_ORIGINS`, `GRAPH_TO_MD_MAX_SYNC_ZIP_MB`, `GRAPH_TO_MD_HOST`, `GRAPH_TO_MD_PORT` (default **8012**) |
481
531
  | 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` |
482
532
  | Video API | `MD_VIDEO_` | Same pattern as audio with `MD_VIDEO_*` (defaults: larger upload/sync caps, port **8012**) |
533
+ | 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 |
483
534
 
484
535
  Exact variable names match the `ApiSettings` / helper functions in each `api/settings` or `api/app` module.
485
536
 
@@ -503,8 +554,12 @@ Two usage patterns:
503
554
  | PPTX | `python -m md_generator.ppt.api.mcp_server` (see module docstring for flags) |
504
555
  | Image | `python -m md_generator.image.api.mcp_server` (see module for CLI) |
505
556
  | URL / HTML | `python -m md_generator.url.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
557
+ | Playwright / SPA | `md-playwright-mcp` or `python -m md_generator.playwright.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
506
558
  | Audio | `md-audio-mcp` or `python -m md_generator.media.audio.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
507
559
  | Video | `md-video-mcp` or `python -m md_generator.media.video.api.mcp_server` — same transports |
560
+ | YouTube | `md-youtube-mcp` or `python -m md_generator.media.youtube.api.mcp_server` — same transports |
561
+ | Database metadata | `md-db-mcp` or `python -m md_generator.db.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
562
+ | Graph (Neo4j / NetworkX) | `md-graph-mcp` or `python -m md_generator.graph.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
508
563
 
509
564
  **Word** and **XLSX** also ship a small runner script in the repo:
510
565
 
@@ -529,7 +584,7 @@ pip install -e ".[dev,all]" # or a smaller subset of extras
529
584
  python -m pytest
530
585
  ```
531
586
 
532
- Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/tests/`); `pyproject.toml` configures `pythonpath = ["src"]` so `md_generator` resolves without a separate `PYTHONPATH`.
587
+ Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/tests/`) and **`graph-to-md/tests/`**; `pyproject.toml` configures `pythonpath = ["src"]` so `md_generator` resolves without a separate `PYTHONPATH`.
533
588
 
534
589
  ---
535
590
 
@@ -539,7 +594,7 @@ Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/test
539
594
  |------|------|
540
595
  | `LICENSE` | MIT license text |
541
596
  | `CODE_OF_CONDUCT.md` | [Contributor Covenant](https://www.contributor-covenant.org/) 2.1 |
542
- | `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/) |
597
+ | `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/); **graph-to-md** under [`graph/`](src/md_generator/graph/) |
543
598
  | `pyproject.toml` | Packaging, extras, CLI entry points, pytest |
544
599
  | `*-to-md/` | **Docs, tests, fixtures**, thin `converter.py` shims, some `run.py` helpers |
545
600
  | `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.3.0"
7
+ version = "0.5.0"
8
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", "database"]
15
15
  classifiers = [
16
16
  "Programming Language :: Python :: 3",
17
17
  "Programming Language :: Python :: 3 :: Only",
@@ -76,6 +76,36 @@ url-full = [
76
76
  audio = ["openai-whisper>=20231117", "imageio-ffmpeg>=0.5.1"]
77
77
  # Same ML stack as audio; ships a bundled ``ffmpeg`` binary when the system has none.
78
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
+ ]
95
+ db = [
96
+ "sqlalchemy>=2.0.0",
97
+ "pyyaml>=6.0.0",
98
+ "psycopg2-binary>=2.9.9",
99
+ "pymysql>=1.1.0",
100
+ "oracledb>=2.0.0",
101
+ "pymongo>=4.6.0",
102
+ "mermaid-py>=0.8.0",
103
+ ]
104
+ graph = [
105
+ "networkx>=3.2.0",
106
+ "neo4j>=5.14.0",
107
+ "pyyaml>=6.0.0",
108
+ ]
79
109
  api = [
80
110
  "fastapi>=0.115.0",
81
111
  "uvicorn[standard]>=0.32.0",
@@ -87,9 +117,15 @@ mcp = ["mcp>=1.2.0", "fastmcp>=2.3.0"]
87
117
  dev = [
88
118
  "pytest>=8.0.0",
89
119
  "httpx>=0.27.0",
120
+ "beautifulsoup4>=4.12.0",
121
+ "lxml>=5.0.0",
122
+ "youtube-transcript-api>=0.6.0",
90
123
  "mdengine[api]",
91
124
  "mdengine[mcp]",
92
125
  "mdengine[url]",
126
+ "mdengine[playwright]",
127
+ "mdengine[db]",
128
+ "mdengine[graph]",
93
129
  ]
94
130
  all = [
95
131
  "pymupdf>=1.24.0",
@@ -116,6 +152,7 @@ all = [
116
152
  "beautifulsoup4>=4.12.0",
117
153
  "lxml_html_clean>=0.4.0",
118
154
  "readability-lxml>=0.8.1",
155
+ "youtube-transcript-api>=0.6.0",
119
156
  ]
120
157
 
121
158
  [project.urls]
@@ -138,10 +175,27 @@ md-audio-api = "md_generator.media.audio.api.run:main"
138
175
  md-video-api = "md_generator.media.video.api.run:main"
139
176
  md-audio-mcp = "md_generator.media.audio.api.mcp_server:main"
140
177
  md-video-mcp = "md_generator.media.video.api.mcp_server:main"
178
+ md-youtube = "md_generator.media.youtube.converter:main"
179
+ md-youtube-api = "md_generator.media.youtube.api.run:main"
180
+ md-youtube-mcp = "md_generator.media.youtube.api.mcp_server:main"
181
+ md-playwright = "md_generator.playwright.cli:main"
182
+ md-playwright-api = "md_generator.playwright.api.run:main"
183
+ md-playwright-mcp = "md_generator.playwright.api.mcp_server:main"
184
+ md-db = "md_generator.db.cli.main:main"
185
+ md-db-api = "md_generator.db.api.run:main"
186
+ md-db-mcp = "md_generator.db.api.mcp_server:main"
187
+ md-graph = "md_generator.graph.cli.main:main"
188
+ md-graph-api = "md_generator.graph.api.run:main"
189
+ md-graph-mcp = "md_generator.graph.api.mcp_server:main"
190
+ mdengine = "md_generator.engine_cli:main"
141
191
 
142
192
  [tool.setuptools.packages.find]
143
193
  where = ["src"]
144
194
 
195
+ [tool.setuptools.package-data]
196
+ "md_generator.db.config" = ["*.yaml"]
197
+ "md_generator.graph.config" = ["*.yaml"]
198
+
145
199
  [tool.pytest.ini_options]
146
200
  pythonpath = ["src"]
147
201
  testpaths = [
@@ -155,5 +209,9 @@ testpaths = [
155
209
  "url-to-md/tests",
156
210
  "audio-to-md/tests",
157
211
  "video-to-md/tests",
212
+ "youtube-to-md/tests",
213
+ "playwright-to-md/tests",
214
+ "db-to-md/tests",
215
+ "graph-to-md/tests",
158
216
  ]
159
217
  markers = ["integration: optional dependency or slower checks"]