Add links

This commit is contained in:
2026-02-06 20:44:53 +00:00
parent 9b2b15c570
commit 46605e5f75
8 changed files with 121 additions and 47 deletions

View File

@@ -1,19 +1,21 @@
#!/usr/bin/python3
import traceback
from os import environ
from os import environ, path
import threading
import logging
import xml.etree.ElementTree as ET
from os import path
from urllib.parse import urlsplit
from re import match
import json
from io import BytesIO
from requests import post
from flask import Flask, render_template, Response, url_for, request
from flask import Flask, render_template, Response, url_for, request, send_from_directory, make_response
from PIL import Image, UnidentifiedImageError
from .content import ContentArea
from .contact import ContactForm
from .storage import LocalStorage
from .links import Links
app = Flask(__name__)
@@ -26,6 +28,7 @@ projects = ContentArea(
app.register_blueprint(projects, url_prefix='/projects')
app.register_blueprint(ContactForm('contact', __name__), url_prefix='/contact')
app.register_blueprint(Links(path.join(md_path, 'links.json'), 'links', __name__), url_prefix='/links')
class DiscordLogger(logging.Handler):
''' Simple logging handler to send a message to Discord '''
@@ -145,3 +148,43 @@ def sitemap():
ET.SubElement(url, 'lastmod').text = article.metadata['date'].strftime('%Y-%m-%d')
return Response(ET.tostring(root, encoding='utf-8'), 200, {'content-type': 'application/xml'})
@app.route('/image/<image_name>')
def image( image_name: str) -> Response:
''' Resize and return an image. '''
md_directory = LocalStorage(md_path)
w = int(request.args.get('w', 0))
h = int(request.args.get('h', 0))
if w == 0 and h == 0:
return send_from_directory(md_directory.uri, path.join('images', image_name))
try:
the_image = Image.open(path.join(md_directory.uri, 'images', image_name))
except FileNotFoundError:
return Response(status=404)
except UnidentifiedImageError:
return send_from_directory(md_directory.uri, path.join('images', image_name))
max_width, max_height = the_image.size
if (w >= max_width and h >= max_height):
return send_from_directory(md_directory.uri, path.join('images', image_name))
if path.exists(path.join('images', f'{w}-{h}-{image_name}')):
return send_from_directory(md_directory.uri, path.join('images', f'{w}-{h}-{image_name}'))
req_size = [max_width, max_height]
if w > 0:
req_size[0] = w
if h > 0:
req_size[1] = h
resized_img = BytesIO()
the_image.thumbnail(tuple(req_size))
the_image.save(resized_img, format=the_image.format)
the_image.save(path.join(md_directory.uri, 'images', f'{w}-{h}-{image_name}'), the_image.format)
response = make_response(resized_img.getvalue())
response.headers.set('Content-Type', f'image/{the_image.format}')
return response

View File

@@ -3,12 +3,10 @@
from os import path
import json
from datetime import datetime
from io import BytesIO
from PIL import Image, UnidentifiedImageError
import frontmatter
from markdown import markdown
from bs4 import BeautifulSoup
from flask import render_template, Response, send_from_directory, request, make_response, Blueprint
from flask import render_template, Response, Blueprint
from .storage import LocalStorage
class ContentArea(Blueprint):
@@ -26,7 +24,7 @@ class ContentArea(Blueprint):
self.add_url_rule('/', view_func=self.projects)
self.add_url_rule('/category/<category_id>/', view_func=self.category)
self.add_url_rule('/<article_id>', view_func=self.article)
self.add_url_rule('/image/<image_name>', view_func=self.image)
#self.add_url_rule('/image/<image_name>', view_func=self.image)
def processor(self) -> dict:
''' Jninja processors '''
@@ -140,41 +138,4 @@ class ContentArea(Blueprint):
the_article = articles[0]
return render_template('article.html', post=markdown(the_article.content),
metadata=the_article.metadata,
page_title=f'{the_article.metadata["title"]} - ')
def image(self, image_name: str) -> Response:
''' Resize and return an image. '''
w = int(request.args.get('w', 0))
h = int(request.args.get('h', 0))
if w == 0 and h == 0:
return send_from_directory(self.md_directory.uri, path.join('images', image_name))
try:
the_image = Image.open(path.join(self.md_directory.uri, 'images', image_name))
except FileNotFoundError:
return Response(status=404)
except UnidentifiedImageError:
return send_from_directory(self.md_directory.uri, path.join('images', image_name))
max_width, max_height = the_image.size
if (w >= max_width and h >= max_height):
return send_from_directory(self.md_directory.uri, path.join('images', image_name))
if path.exists(path.join('images', f'{w}-{h}-{image_name}')):
return send_from_directory(self.md_directory.uri, path.join('images', f'{w}-{h}-{image_name}'))
req_size = [max_width, max_height]
if w > 0:
req_size[0] = w
if h > 0:
req_size[1] = h
resized_img = BytesIO()
the_image.thumbnail(tuple(req_size))
the_image.save(resized_img, format=the_image.format)
the_image.save(path.join(self.md_directory.uri, 'images', f'{w}-{h}-{image_name}'), the_image.format)
response = make_response(resized_img.getvalue())
response.headers.set('Content-Type', f'image/{the_image.format}')
return response
page_title=f'{the_article.metadata["title"]} - ')

13
src/jakecharman/links.py Normal file
View File

@@ -0,0 +1,13 @@
from flask import Blueprint, render_template
import json
class Links(Blueprint):
def __init__(self, file, *args, **kwargs):
super().__init__(*args, **kwargs)
self.add_url_rule('/', view_func=self.links)
self.file = file
def links(self):
with open(self.file, encoding='utf8') as file:
links = json.load(file)
return render_template('links.html', links=links, page_title='Useful Links - ')

View File

@@ -30,6 +30,7 @@
<a href="/">About</a>
<a href="/projects/">Projects</a>
<a href="/contact/">Contact</a>
<a href="/links/">Links</a>
</nav>
<div id="logo-container">
<div id="logo">

View File

@@ -0,0 +1,28 @@
{% include 'header.html' %}
<main id="links-main">
<h2>Useful Links</h2>
<section id="links">
{% for link in links %}
<div class="link">
{% if link.get('img') is not none %}
<a href="{{link.src}}" target="_blank"></a>
<img class="link-thumb"
srcset="
{% for i in range(200, 5100, 100) %}
/image/{{ link.img }}?w={{i}} {{i}}w{{"," if not loop.last}}
{% endfor %}
"
sizes="
(max-width: 999px) 80vw,
(min-width: 1000px) 20vw
"
src="/image/{{ link.img }}">
</a>
{% endif %}
<a href="{{link.src}}" target="_blank"><h3>{{ link.title }}</h3></a>
<p>{{ link.description }}</p>
</div>
{% endfor %}
</section>
</main>
{% include 'footer.html' %}

View File

@@ -24,14 +24,14 @@
<img class="project-thumb"
srcset="
{% for i in range(200, 5100, 100) %}
/projects/image/{{ row.image }}?w={{i}} {{i}}w{{"," if not loop.last}}
/image/{{ row.image }}?w={{i}} {{i}}w{{"," if not loop.last}}
{% endfor %}
"
sizes="
(max-width: 999px) 80vw,
(min-width: 1000px) 20vw
"
src="/projects/image/{{ row.image }}">
src="/image/{{ row.image }}">
</a>
<div class="project-text">
{% if row.get('link') is not none %}

View File

@@ -114,4 +114,12 @@
.gallery>img {
width: calc(33% - 40px);
}
#links {
padding-left: 20px;
padding-right: 20px;
}
.link>a>h3 {
padding-top: 20px;
}
}

View File

@@ -281,4 +281,24 @@ pre{
.gallery * {
padding: 10px;
max-width: 80vw;
}
#links-main{
padding: 20px 10px 0 10px;
min-height: 65vh;
}
.link {
border-top: 1px solid #e5e5e5;
}
.link>img {
float: left;
padding-right: 20px;
max-width: 100px;
}
.link>a>h3 {
padding-top: 10px;
margin: 0
}