Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ https://python.microformats.io

## Deployment

All commits to the `master` branch get auto-deployed to the live website (running on [Heroku](https://python.microformats.io))
All commits to the `main` branch get auto-deployed to the live website (running on [Heroku](https://python.microformats.io))

## Getting Started

Expand All @@ -15,8 +15,8 @@ This website is built using Python Flask.
To start working with this project, first clone the repository for this project:

```
git clone https://github.com/indieweb/microformats-python-parser-website.git
cd microformats-python-parser-website
git clone https://github.com/microformats/microformats-parser-website-python.git
cd microformats-parser-website-python
```

Next, install the required dependencies:
Expand All @@ -32,6 +32,8 @@ uv run -- app.py --debug (debug mode)
uv run -- gunicorn --bind localhost:8080 app:app (production mode)
```

In debug mode the port defaults to 8080; use `-p`/`--port` to change it.

You can view your running local application at this URL:

```
Expand All @@ -40,19 +42,20 @@ http://localhost:8080

## Requirements

- Python 3.9
- Python 3.14.5
- [uv](https://docs.astral.sh/uv/)

## Contributions

1. Fork it
2. Get it running (see Installation above)
2. Get it running (see Getting Started above)
3. Create your feature branch (`git checkout -b my-new-feature`)
4. Commit your changes (`git commit -am 'Add some feature'`)
5. Push to the branch (`git push origin my-new-feature`)
6. Create new Pull Request

If you find bugs, have feature requests or questions, please
[file an issue](https://github.com/indieweb/microformats-parser-website-python/issues).
[file an issue](https://github.com/microformats/microformats-parser-website-python/issues).

## License

Expand All @@ -63,4 +66,5 @@ http://creativecommons.org/publicdomain/zero/1.0
## Contributors

- Kyle Mahan / [@kylewm](https://github.com/kylewm) (Author)
- [@capjamesg](https://github.com/capjamesg) (Contributor)
- [@capjamesg](https://github.com/capjamesg) (Contributor)
- Martijn van der Ven / [@Zegnat](https://github.com/Zegnat) (Contributor)
12 changes: 11 additions & 1 deletion app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
import tomllib
import traceback
from collections import OrderedDict
from pathlib import Path

import mf2py
import mf2util
Expand All @@ -11,6 +13,10 @@
mf2py.Parser.user_agent = "python.microformats.io (mf2py/" + mf2py.__version__ + ") Mozilla/5.0 Chrome/29.0.1547.57 Safari/537.36"
mf2py.Parser.dict_class = OrderedDict

SITE_VERSION = tomllib.loads(
(Path(__file__).parent / "pyproject.toml").read_text(encoding="utf-8")
)["project"]["version"]

@app.route("/", methods=["GET", "POST"])
def index():
try:
Expand Down Expand Up @@ -50,7 +56,11 @@ def fetch_mf2(url):
response.headers["Content-Type"] = "application/json"
return response

return render_template("index.jinja2", mf2py_version=mf2py.__version__)
return render_template(
"index.jinja2",
site_version=SITE_VERSION,
mf2py_version=mf2py.__version__,
)
except BaseException as e:
traceback.print_exc()
return jsonify(error="%s: %s" % (type(e).__name__, e)), 400
Expand Down
204 changes: 106 additions & 98 deletions templates/index.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -6,115 +6,123 @@

<title>Python Microformats Parser</title>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<style>
form label {
font-weight: bold;
display: block;
}

form textarea,
form input[type=url] {
font-family: "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}

form .form-control:disabled {
cursor: default;
background: #efefef;
color: black;
}

.help {
color: #999;
font-weight: normal;
}

#json {
font-size: 0.7em;
}

/* disable bootstrap animations */
.form-control, .btn {
transition: none;
}
</style>
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<link rel="icon" href="https://microformats.io/assets/images/microformats-logo.svg" type="image/svg+xml">
</head>

<body>
<main id="mf2" class="container">

<h1 class="mt-5 mb-3">
Microformats Parser (Python)
{{ mf2py_version }}
</h1>

<form action="/" accept-charset="UTF-8" method="get">
<div class="form-group">
<label for="url">Enter a URL</label>
<input required id="url" class="form-control form-control-lg" type="url" name="url" placeholder="https://example.com/person.html" />
</div>

<div class="form-group">
<label for="parser">Parser</label>
<select id="parser" name="parser">
<option>html5lib</option>
<option>lxml</option>
<option>html.parser</option>
</select>
</div>

<div class="form-check">
<label title="mf2util interprets certain post types (currently h-entry and h-event) and returns a normalized result" class="form-check-label" for="util">
<input id="util" name="util" class="form-check-input" type="checkbox" value="true">
Process with mf2util
</label>
</div>

<button type="submit" class="btn btn-lg btn-success">Parse</button>
</form>

<h2 class="h4 my-5">OR parse just a snippet of HTML</h2>

<form method="post" action="/" class="mb-5">
<div class="form-group">
<label for="doc">HTML</label>
<textarea required id="doc" name="doc" rows="6" class="form-control form-control-lg"></textarea>
</div>

<div class="form-group">
<label for="base-url">Base URL</label>
<input id="base-url" name="url" type="url" class="form-control form-control-lg" />
</div>

<div class="form-group">
<label for="doc-parser">Parser</label>
<select id="doc-parser" name="parser">
<option>html5lib</option>
<option>lxml</option>
<option>html.parser</option>
</select>
</div>

<button type="submit" class="btn btn-lg btn-success">Parse</button>
</form>
<div class="container">
<h1 class="mt-5 mb-3">Microformats Parser (Python)</h1>

<main>

<section class="mb-5">
<h2 class="h4">Parse a URL</h2>

<form action="/" accept-charset="UTF-8" method="get">
<div class="mb-3">
<label for="url" class="form-label fw-bold">Enter a URL</label>
<input required id="url" class="form-control form-control-lg font-monospace" type="url" name="url" placeholder="https://example.com/person.html" />
</div>

<div class="mb-3">
<label for="parser" class="form-label fw-bold">Parser</label>
<div class="col-md-4">
<select id="parser" name="parser" class="form-select form-select-lg">
<option>html5lib</option>
<option>lxml</option>
<option>html.parser</option>
</select>
</div>
</div>

<div class="form-check mb-3">
<input id="util" name="util" class="form-check-input" type="checkbox" value="true" aria-describedby="util-help">
<label class="form-check-label fw-bold" for="util">
Process with mf2util
</label>
<div id="util-help" class="form-text">mf2util interprets certain post types (currently h-entry and h-event) and returns a normalized result.</div>
</div>

<button type="submit" class="btn btn-lg btn-success">Parse</button>
</form>
</section>

<section class="mb-5">
<h2 class="h4 mb-5">OR parse just a snippet of HTML</h2>

<form method="post" action="/">
<div class="mb-3">
<label for="doc" class="form-label fw-bold">HTML</label>
<textarea required id="doc" name="doc" rows="6" class="form-control form-control-lg font-monospace"></textarea>
</div>

<div class="mb-3">
<label for="base-url" class="form-label fw-bold">Base URL</label>
<input id="base-url" name="url" type="url" class="form-control form-control-lg font-monospace" />
</div>

<div class="mb-3">
<label for="doc-parser" class="form-label fw-bold">Parser</label>
<div class="col-md-4">
<select id="doc-parser" name="parser" class="form-select form-select-lg">
<option>html5lib</option>
<option>lxml</option>
<option>html.parser</option>
</select>
</div>
</div>

<button type="submit" class="btn btn-lg btn-success">Parse</button>
</form>
</section>

<section class="card mb-5">
<div class="card-body">
<h2 class="h4 card-title">Bookmarklet</h2>
<p class="card-text">Drag this link to your bookmarks toolbar to parse a page with one click!</p>
<a class="btn btn-primary btn-sm" href="javascript:(function(){document.location.href='https://python.microformats.io/?url='+encodeURIComponent(document.location.href);}())" onclick="event.preventDefault()">mf2 parser</a>
</div>
</section>

</main>

<footer class="my-5">
<ul>
<li><a href="https://microformats.io">About Microformats</a></li>
<li><a href="https://github.com/microformats/microformats-parser-website-python">Source code for this site</a></li>
<li><a href="https://github.com/microformats/mf2py">Source code for the Microformats mf2py Parser</a></li>

<li>
<ul class="d-xl-flex flex-xl-wrap">
<li class="col-xl-6 order-xl-1"><a href="https://microformats.io">About Microformats</a></li>
<li class="col-xl-6 order-xl-2">
<a href="https://github.com/microformats/microformats-parser-website-python">Source code for this site</a>
<span class="badge text-bg-light">v{{ site_version }}</span>
</li>
<li class="col-xl-6 order-xl-4">
<a href="https://github.com/microformats/mf2py">Source code for the Microformats mf2py Parser</a>
<span class="badge text-bg-light">v{{ mf2py_version }}</span>
</li>
<li id="parser-list" class="col-xl-6 order-xl-3">
Other Microformats Parser websites:
<a href="https://go.microformats.io">Go</a>,
<a href="https://node.microformats.io">Node</a>,
<a href="https://php.microformats.io">PHP</a>, and
<a href="https://ruby.microformats.io">Ruby</a>.
<a href="https://php.microformats.io">PHP</a>,
<a href="https://ruby.microformats.io">Ruby</a>, and
<a href="https://rust.microformats.io">Rust</a>.
</li>
<li class="col-xl-6 order-xl-5"><a href="https://microformats.org/wiki/microformats2#Parsers">More Microformats parsers</a></li>
</ul>
<p class="text-center mt-5 pt-5">
<a href="https://creativecommons.org/publicdomain/zero/1.0" rel="license" class="link-secondary link-underline-opacity-25">CC0</a>
</p>
</footer>

</main>
<script type="module">
const nodeList = document.getElementById("parser-list").querySelectorAll("a");
const values = Array
.from(nodeList, (node) => [Math.random(), node.href, node.innerText])
.toSorted(([v1], [v2]) => v2 - v1);
nodeList.forEach((node, ix) => {
node.href = values[ix][1];
node.innerText = values[ix][2];
});
</script>
</div>
</body>
</html>