diff --git a/README.rst b/README.rst index 1259f9a..b18abec 100644 --- a/README.rst +++ b/README.rst @@ -1,9 +1,14 @@ +.. image:: https://raw.githubusercontent.com/PtPrashantTripathi/markdown-server/master/markdownserver-logo.webp + :alt: "Markdown Server Logo" + :width: 300px + :align: center + =============== Markdown Server =============== Markdown-server is a simple web application. -It converts markdown file to HTML and response by `text/html`. +It converts markdown files to HTML and responds with `text/html`. How to use ========== @@ -29,8 +34,18 @@ Just try Start server ------------ -You don't need any special preparation to try to start server. Just execute below commands. +You can install `markdown-server` from **PyPi** or run it directly from the repository. +### Install from PyPi: +:: + + (.venv)$ pip install markdown-server + (.venv)$ markdownserver --host localhost --port 8009 --debug + + Bottle v0.12.8 server starting up (using WSGIRefServer())... + Listening on http://localhost:8009/ + +### Install from GitHub: :: $ git clone https://github.com/ohbarye/markdown-server @@ -38,54 +53,93 @@ You don't need any special preparation to try to start server. Just execute belo $ virtualenv .venv $ source .venv/bin/activate (.venv)$ pip install -r requirements.txt - (.venv)$ markdownserver + (.venv)$ markdownserver --host localhost --port 8009 --debug Bottle v0.12.8 server starting up (using WSGIRefServer())... Listening on http://localhost:8009/ -Or, you can install from PyPi. +If the server starts up successfully, browse the below URL and check the converted result. :: - (.venv)$ pip install markdown-server - (.venv)$ markdownserver - Bottle v0.12.8 server starting up (using WSGIRefServer())... - Listening on http://localhost:8009/ + $ open http://localhost:8009/sample.md +MarkdownServer CLI +------------------ -If server start up successfully, browse below URL and check the converted result. +You can run the `markdownserver` command to start the server with the following examples: +### Example 1: Using Default Arguments :: - $ open http://localhost:8009/sample.md + (.venv)$ markdownserver + +This will run the server on the default host (`localhost`) and port (`8009`), with debugging disabled. + +### Example 2: Custom Host, Port, and Debug +:: + + (.venv)$ markdownserver --host 0.0.0.0 --port 8080 --debug + +This will run the server on `0.0.0.0:8080` with debugging enabled, allowing you to access the server from any device on your local network. + +**Arguments:** +- `--host`: Specify the host to run the server on (default is `localhost`). +- `--port`: Specify the port to run the server on (default is `8009`). +- `--debug`: Enable or disable debugging mode (default is `False`). Only Conversion --------------- -Additionally, You can use the conversion function alone. +Additionally, you can use the conversion function alone from the command line. + +:: + + (.venv)$ markdownconvert source_md_file target_html_file + +This will convert the provided markdown file (`source_md_file`) into an HTML file (`target_html_file`). + +MarkdownConverter CLI +--------------------- + +The `markdownconvert` command can be used with the following options: :: - (.venv)$ convert source_md_file target_html_file + $ markdownconvert source_md_file target_html_file + +**Arguments:** +- `source_md_file`: The markdown file you want to convert to HTML. +- `target_html_file`: The output HTML file to save the converted content. + +Example: + +:: + + $ markdownconvert sample.md sample.md.html + +This will convert the `sample.md` file into a `sample.md.html` file in the current directory. -------------- Do as you like -------------- -- Markdown server purvey `http://host/[file_name]` URL. This corresponds to `resources/markdown/[file_name]`.You can put any markdown file here. - -- Converted file will be placed to `resources/html` directory. Generated html file includes CSS so it's ease to distribute. - -- Environment variables like *host name* or *port number* are set in `env.py`. Edit arbitrarily. +- The Markdown server provides `http://host/[file_name]` URL. You can place any markdown file here. - :: +- The converted HTML file will be placed in the `resources/html` directory. The generated HTML file includes CSS for easy distribution. - ms_port = '8009' - ms_host = 'localhost' +Developers Information +====================== +1. **Masato Ohba** + - GitHub: `@ohbarye ` + .. image:: https://avatars.githubusercontent.com/u/1811616 + :alt: "Masato Ohba" + :width: 200px -- The default markdown engine is Github flavored Markdown. If you want to use another style, add CSS and edit `env.py`. +2. **Pt. Prashant Tripathi** + - GitHub: `@ptprashanttripathi ` + .. image:: https://avatars.githubusercontent.com/u/26687933 + :alt: "Pt. Prashant Tripathi" + :width: 200px - :: - css_name = 'github.css' - markdown_type = 'gfm' diff --git a/markdownserver-logo.webp b/markdownserver-logo.webp new file mode 100644 index 0000000..c0bf766 Binary files /dev/null and b/markdownserver-logo.webp differ diff --git a/markdownserver/__init__.py b/markdownserver/__init__.py index 7495211..08c656f 100644 --- a/markdownserver/__init__.py +++ b/markdownserver/__init__.py @@ -1,32 +1,8 @@ -from __future__ import absolute_import -from bottle import route, run, static_file from .markdown_converter import MarkdownConverter -from .env import root_path, ms_host, ms_port, ms_debug -import os +from .markdown_server import MarkdownServer -converter = MarkdownConverter() - - -@route(r'/') -def gfmize(resource): - if resource == 'favicon.ico': - return '' - - html_file_name = os.path.basename(converter.convert(resource)) - if '/' in resource: - html_file_name = '/'.join(resource.split('/')[:-1]) + \ - '/' + html_file_name - return static_file(os.path.join('resources/html', - html_file_name), - root=root_path) - - -def main(): - run(host=ms_host, - port=ms_port, - debug=ms_debug, - reloader=False) - - -if __name__ == '__main__': - main() +__author__ = [ + {"name": "Masato Ohba", "email": "over.rye@gmail.com"}, + {"name": "Pt. Prashant Tripathi", "email": "ptprashanttripathi@outlook.com"}, +] +__all__ = ["MarkdownServer", "MarkdownConverter"] diff --git a/markdownserver/markdown_converter.py b/markdownserver/markdown_converter.py index 24885b1..b97e0b3 100644 --- a/markdownserver/markdown_converter.py +++ b/markdownserver/markdown_converter.py @@ -1,16 +1,14 @@ -from __future__ import print_function -from __future__ import absolute_import -from builtins import object -import markdown as md -import codecs import sys import os -from .env import css_path, ms_encoding, markdown_type, \ - html_dir, html_extension +import markdown as md +import codecs +import argparse +from markdownserver.env import css_path, ms_encoding, markdown_type, html_dir, html_extension -class MarkdownConverter(object): +class MarkdownConverter: def __init__(self): + """Initialize the converter with the CSS header and footer.""" css = codecs.open(css_path, encoding=ms_encoding, mode="r") self.html_header = ( """ @@ -35,21 +33,21 @@ def __init__(self): """ def convert(self, src, dst=""): + """Convert a Markdown file to HTML.""" code = md.markdown(self.read_md(src), extensions=[markdown_type]) return self.write_html(code, src, dst) def read_md(self, file_name): + """Read the contents of a Markdown file.""" workingdir = os.getcwd() md_file = codecs.open( - os.path.join(workingdir, file_name), - encoding=ms_encoding, - mode="r" + os.path.join(workingdir, file_name), encoding=ms_encoding, mode="r" ) return md_file.read() def write_html(self, body, file_name, dst): + """Write HTML content to a file.""" html_path = os.path.join(html_dir, file_name + html_extension) - if dst != "": html_path = dst try: @@ -63,12 +61,29 @@ def write_html(self, body, file_name, dst): def main(): - args = sys.argv - if len(args) != 3: - print("usage: convert source_md_file target_html_file") - else: - converter = MarkdownConverter() - converter.convert(args[1], args[2]) + """CLI entry point to convert a Markdown file to HTML using argparse.""" + parser = argparse.ArgumentParser( + description="Convert a Markdown file to an HTML file with styling." + ) + parser.add_argument( + "source_md_file", + metavar="SOURCE_MD_FILE", + help="The source Markdown file to convert", + ) + parser.add_argument( + "target_html_file", + metavar="TARGET_HTML_FILE", + help="The destination HTML file to save", + ) + + args = parser.parse_args() + + # Convert the given Markdown file to HTML + converter = MarkdownConverter() + html_path = converter.convert(args.source_md_file, args.target_html_file) + print( + f"Markdown file '{args.source_md_file}' converted to HTML and saved as '{html_path}'" + ) if __name__ == "__main__": diff --git a/markdownserver/markdown_server.py b/markdownserver/markdown_server.py new file mode 100644 index 0000000..825864d --- /dev/null +++ b/markdownserver/markdown_server.py @@ -0,0 +1,122 @@ +import os +from http.server import SimpleHTTPRequestHandler, HTTPServer +from markdownserver.markdown_converter import MarkdownConverter +from markdownserver.env import ms_host, ms_port, ms_debug + + +class MarkdownServerHandler(SimpleHTTPRequestHandler): + """ + Custom HTTP request handler that dynamically converts Markdown (.md) files to HTML + when accessed via a browser. Non-Markdown files are served as-is. + """ + + def do_GET(self): + """ + Handle GET requests. + - If the requested file is a Markdown file, convert it to HTML and serve it. + - Otherwise, serve the file normally. + """ + # Get the file path + filepath = self.translate_path(self.path) + + # Check if the requested file is a Markdown file + if os.path.isfile(filepath) and filepath.endswith(".md"): + self.serve_markdown(filepath) + else: + super().do_GET() + + def serve_markdown(self, filepath): + """ + Serve a Markdown file as HTML content. + + Args: + filepath (str): The path to the Markdown file. + """ + try: + # Create an instance of the MarkdownConverter + converter = MarkdownConverter() + + # Convert the Markdown file to HTML + html_path = converter.convert(filepath) + + # Read the generated HTML content + with open(html_path, "r", encoding="utf-8") as html_file: + html_content = html_file.read() + + # Send the response headers + self.send_response(200) + self.send_header("Content-type", "text/html; charset=utf-8") + self.end_headers() + + # Write the HTML content to the response + self.wfile.write(html_content.encode("utf-8")) + + except Exception as e: + self.send_error(500, f"Error processing Markdown file: {e}") + + +class MarkdownServer: + """ + A simple HTTP server for serving files, with special handling for Markdown files. + """ + + def __init__(self, host=None, port=None, debug=False): + """ + Initialize the server. + + Args: + host (str): Hostname to bind the server to. Default is 'localhost'. + port (int): Port to bind the server to. Default is 8000. + debug (bool): Enable/Disable debug mode. Default is False. + """ + # Use environment variables or defaults for host and port + self.host = host or ms_host + self.port = int(port or ms_port) + self.debug = debug or ms_debug + self.server_address = (self.host, self.port) + self.httpd = HTTPServer(self.server_address, MarkdownServerHandler) + + def start(self): + """ + Start the HTTP server and begin serving requests. + """ + print(f"Markdown server is running on http://{self.host}:{self.port}") + self.httpd.serve_forever() + + def stop(self): + """ + Stop the HTTP server. + """ + print("Shutting down the server...") + self.httpd.server_close() + + +def main(): + """ + Main function to run the server with command-line arguments for host, port, and debug. + """ + import argparse + + # Setup CLI arguments + parser = argparse.ArgumentParser(description="Start the markdown HTTP server.") + parser.add_argument("--host", help="Host to bind the server (default: localhost)") + parser.add_argument( + "--port", type=int, help="Port to bind the server (default: 8000)" + ) + parser.add_argument( + "--debug", action="store_true", help="Enable debug mode (default: False)" + ) + + args = parser.parse_args() + + # Create an instance of the server with provided or default arguments + server = MarkdownServer(host=args.host, port=args.port, debug=args.debug) + + try: + server.start() + except KeyboardInterrupt: + server.stop() + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3f4000b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,35 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "markdown-server" +version = "0.2.1" +description = "Simple markdown server written in Python. It converts your markdown file to HTML and returns a response as text/html." +readme = "README.rst" +authors = [ + {name = "Masato Ohba", email = "over.rye@gmail.com"}, + {name = "Pt. Prashant Tripathi", email = "ptprashanttripathi@outlook.com"} +] +license = {text = "MIT License"} +keywords = ["web", "markdown", "md", "server", "markdownserver", "markdownconvert"] +classifiers = [ + "Topic :: Utilities", + "Development Status :: 4 - Beta", + "Framework :: Bottle", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3" +] +dependencies = ["bottle", "Markdown==2.6.11", "Pygments", "py-gfm"] + +[project.scripts] +markdownserver = "markdownserver.markdown_server:main" +markdownconvert = "markdownserver.markdown_converter:main" + +[project.urls] +Homepage = "https://github.com/ohbarye/markdown-server" + +[tool.setuptools.package-data] +"markdownserver" = ["*"] diff --git a/requirements.txt b/requirements.txt index 495d438..309ce83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,6 @@ bottle==0.12.19 linecache2==1.0.0 Markdown==2.6.2 --e git+https://github.com/ohbarye/markdown-server@f85a63ba06ca7cb5beb59bd96153d7ba1fa867ae#egg=markdownserver-master py-gfm==0.1.0 Pygments==2.7.4 six==1.9.0 diff --git a/setup.py b/setup.py deleted file mode 100644 index 4518785..0000000 --- a/setup.py +++ /dev/null @@ -1,42 +0,0 @@ -import os -from setuptools import setup, find_packages - - -def read_file(filename): - basepath = os.path.dirname(os.path.dirname(__file__)) - filepath = os.path.join(basepath, filename) - if os.path.exists(filepath): - return open(filepath).read() - else: - return "" - - -setup( - name="markdown-server", - version="0.1.4", - description="A simple markdown server.", - long_description=read_file("README.rst"), - author="Masato Ohba", - author_email="over.rye@gmail.com", - url="https://github.com/ohbarye/markdown-server", - classifiers=[ - "Topic :: Utilities", - "Development Status :: 4 - Beta", - "Framework :: Bottle", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - ], - packages=find_packages(), - include_package_data=True, - keywords=["web", "markdown"], - license="MIT License", - install_requires=["bottle", "Markdown==2.6.11", "Pygments", "py-gfm"], - entry_points={ - "console_scripts": [ - "markdownserver=markdownserver:main", - "convert=markdownserver.markdown_converter:main", - ] - }, -)