Init repository
This commit is contained in:
commit
0e2fcf3195
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
html
|
||||||
|
result
|
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Chaos Events
|
||||||
|
|
||||||
|
This repository contains code that generates the [Chaos Events Website](https://chaosevents.clerie.de).
|
||||||
|
|
||||||
|
If fetches an ICS from a URL and generates html files that get placed in a specified directory.
|
||||||
|
|
||||||
|
## Use with pip
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install .
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
chaosevents path/to/out/directory
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use with flake
|
||||||
|
|
||||||
|
```
|
||||||
|
nix run . -- path/to/out/directory
|
||||||
|
```
|
43
assets/style.css
Normal file
43
assets/style.css
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin-top: 40px;
|
||||||
|
margin-bottom: 80px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin-top: 40px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
section h3 .date {
|
||||||
|
font-size: medium;
|
||||||
|
color: dimgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
section .description {
|
||||||
|
padding: 10px;
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
77
chaosevents.py
Executable file
77
chaosevents.py
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import arrow
|
||||||
|
from ics import Calendar
|
||||||
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
|
from markdown2 import Markdown
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
|
||||||
|
basepath = Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader(basepath / "templates"),
|
||||||
|
autoescape=select_autoescape()
|
||||||
|
)
|
||||||
|
|
||||||
|
def render_markdown(text):
|
||||||
|
pattern = re.compile(
|
||||||
|
r"""
|
||||||
|
\b
|
||||||
|
(
|
||||||
|
(?:https?://|(?<!//)www\.) # prefix - https:// or www.
|
||||||
|
\w[\w_\-]*(?:\.\w[\w_\-]*)* # host
|
||||||
|
[^<>\s"']* # rest of url
|
||||||
|
(?<![?!.,:*_~);]) # exclude trailing punctuation
|
||||||
|
(?=[?!.,:*_~);]?(?:[<\s]|$)) # make sure that we're not followed by " or ', i.e. we're outside of href="...".
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
re.X
|
||||||
|
)
|
||||||
|
|
||||||
|
markdown = Markdown(
|
||||||
|
extras=["link-patterns"],
|
||||||
|
link_patterns=[(pattern, r'\1')]
|
||||||
|
)
|
||||||
|
|
||||||
|
return markdown.convert('' if text is None else text)
|
||||||
|
|
||||||
|
def main(ics_url, out_path):
|
||||||
|
|
||||||
|
(out_path / "style.css").write_text((basepath / "assets" / "style.css").read_text())
|
||||||
|
|
||||||
|
r = requests.get(ics_url)
|
||||||
|
|
||||||
|
|
||||||
|
c = Calendar(r.text)
|
||||||
|
t = c.timeline
|
||||||
|
|
||||||
|
for e in t:
|
||||||
|
e.description_rendered = render_markdown(e.description)
|
||||||
|
|
||||||
|
(out_path / "chaosevents.ics").write_text(r.text)
|
||||||
|
|
||||||
|
(out_path / "index.html").write_text(
|
||||||
|
env.get_template("index.html").render(
|
||||||
|
currentevents=t.now() if any(t.now()) else None,
|
||||||
|
upcomingevents=t.start_after(arrow.utcnow())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def cli():
|
||||||
|
ics_url = "https://cloud.fem.tu-ilmenau.de/remote.php/dav/public-calendars/Q58G8xM52HXPc6Jj/?export"
|
||||||
|
|
||||||
|
out_path = Path("html")
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
out_path = Path(sys.argv[1])
|
||||||
|
|
||||||
|
out_path.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
main(ics_url, out_path)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
cli()
|
27
flake.lock
Normal file
27
flake.lock
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1686501370,
|
||||||
|
"narHash": "sha256-G0WuM9fqTPRc2URKP9Lgi5nhZMqsfHGrdEbrLvAPJcg=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "75a5ebf473cd60148ba9aec0d219f72e5cf52519",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
40
flake.nix
Normal file
40
flake.nix
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
outputs = { self, nixpkgs, ... }: {
|
||||||
|
packages.x86_64-linux = let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
chaosevents = pkgs.python311Packages.buildPythonPackage rec {
|
||||||
|
pname = "chaosevents";
|
||||||
|
version = "0.0.1";
|
||||||
|
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
format = "pyproject";
|
||||||
|
|
||||||
|
buildInputs = [ pkgs.python311Packages.hatchling ];
|
||||||
|
propagatedBuildInputs = with pkgs.python311Packages; [ attrs ics jinja2 markdown2 requests ];
|
||||||
|
|
||||||
|
pythonImportsCheck = [ "chaosevents" ];
|
||||||
|
};
|
||||||
|
default = self.packages.x86_64-linux.chaosevents;
|
||||||
|
};
|
||||||
|
|
||||||
|
apps.x86_64-linux = {
|
||||||
|
chaosevents = {
|
||||||
|
type = "app";
|
||||||
|
program = self.packages.x86_64-linux.chaosevents + "/bin/chaosevents";
|
||||||
|
};
|
||||||
|
default = self.apps.x86_64-linux.chaosevents;
|
||||||
|
};
|
||||||
|
|
||||||
|
hydraJobs = {
|
||||||
|
inherit (self)
|
||||||
|
packages;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
34
pyproject.toml
Normal file
34
pyproject.toml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "chaosevents"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = [
|
||||||
|
{ name="clerie", email="hallo@clerie.de" },
|
||||||
|
]
|
||||||
|
description = ""
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
"ics",
|
||||||
|
"jinja2",
|
||||||
|
"markdown2",
|
||||||
|
"requests",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
chaosevents = "chaosevents:cli"
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
"Source" = "https://git.clerie.de/clerie/chaosevents"
|
||||||
|
|
||||||
|
[tool.hatch.build]
|
||||||
|
include = [
|
||||||
|
"*.py",
|
||||||
|
"assets",
|
||||||
|
"templates",
|
||||||
|
]
|
||||||
|
|
43
templates/index.html
Normal file
43
templates/index.html
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Upcoming Chaos Events</title>
|
||||||
|
<link rel="stylesheet" href="/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<h1>Chaos Events</h1>
|
||||||
|
<div>
|
||||||
|
<a href="/chaosevents.ics">Add to calendar</a> | <a href="mailto:chaosevents@clerie.de"> Event missing?</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
{% if currentevents %}
|
||||||
|
<section>
|
||||||
|
<h2>Current</h2>
|
||||||
|
</section>
|
||||||
|
{% for event in currentevents %}
|
||||||
|
<section>
|
||||||
|
<h3>{{ event.name }} <span class="date">{{ event.begin.format("YYYY-MM-DD") }} - {{ event.end.shift(seconds=-1).format("YYYY-MM-DD") }}</span></h3>
|
||||||
|
<div class="description">
|
||||||
|
{{ event.description_rendered|safe }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
<section>
|
||||||
|
<h2>Upcoming</h2>
|
||||||
|
</section>
|
||||||
|
{% for event in upcomingevents %}
|
||||||
|
<section>
|
||||||
|
<h3>{{ event.name }} <span class="date">{{ event.begin.format("YYYY-MM-DD") }} - {{ event.end.shift(seconds=-1).format("YYYY-MM-DD") }}</span></h3>
|
||||||
|
<div class="description">
|
||||||
|
{{ event.description_rendered|safe }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endfor %}
|
||||||
|
<footer>
|
||||||
|
<a href="https://legal.clerie.de/impressum">Imprint</a> | <a href="https://legal.clerie.de/datenschutz">Privacy</a>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
Loading…
Reference in New Issue
Block a user