Browse Source

wanders & mod time added

master
Cailean Finn 4 months ago
parent
commit
e825506bbd
  1. 26
      build.py
  2. 10
      public/about.html
  3. 11
      public/articles/(o)machine.html
  4. 9
      public/articles/ai-x-body.html
  5. 9
      public/articles/beauty-and-the-beep.html
  6. 9
      public/articles/data.html
  7. 9
      public/articles/demo.html
  8. 9
      public/articles/dwelling.html
  9. 9
      public/articles/electronic-image.html
  10. 9
      public/articles/latent-mirror.html
  11. 9
      public/articles/undefined.html
  12. 36
      public/css/styles.css
  13. 9
      public/js/wander.js
  14. 99
      server.js
  15. 5
      templates/_modified.html
  16. 4
      templates/_wanderers.html
  17. 3
      templates/about.html
  18. 5
      templates/article.html

26
build.py

@ -3,6 +3,7 @@ import markdown
import re import re
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
import yaml import yaml
import time
import json import json
class Website: class Website:
@ -14,7 +15,7 @@ class Website:
self.pages = [] self.pages = []
self.tags = [] self.tags = []
self.all_images = [] self.all_images = []
self.about_meta, self.about_content = self.fetch_page('content', 'about.md') self.about_meta, self.about_content, self.about_modified_time = self.fetch_page('content', 'about.md')
def build(self): def build(self):
self.fetch_pages() self.fetch_pages()
@ -30,6 +31,8 @@ class Website:
if page.endswith('.md'): if page.endswith('.md'):
with open(os.path.join('content/posts', page), 'r', encoding="utf8") as f: with open(os.path.join('content/posts', page), 'r', encoding="utf8") as f:
content = f.read() content = f.read()
file_desc = f.fileno()
file_status = os.fstat(file_desc)
parts = content.split('---') parts = content.split('---')
metadata = yaml.safe_load(parts[1]) metadata = yaml.safe_load(parts[1])
md_content = ''.join(parts[2:]) md_content = ''.join(parts[2:])
@ -37,7 +40,7 @@ class Website:
md_content = self.format_content(md_content) md_content = self.format_content(md_content)
html_content = markdown.markdown(md_content) html_content = markdown.markdown(md_content)
output_filename = os.path.splitext(page)[0] + '.html' output_filename = os.path.splitext(page)[0] + '.html'
new_page = Page(metadata, html_content, output_filename) new_page = Page(metadata, html_content, output_filename, file_status)
self.pages.append(new_page) self.pages.append(new_page)
def process_page(self): def process_page(self):
@ -55,6 +58,7 @@ class Website:
image=metadata.get('image', ''), # Assuming image is a string image=metadata.get('image', ''), # Assuming image is a string
showcase=metadata.get('showcase', []), showcase=metadata.get('showcase', []),
credits=metadata.get('credits', []), # Assuming credits is a string credits=metadata.get('credits', []), # Assuming credits is a string
modified_time=page.get_modified_time_readable(),
content=html_content) content=html_content)
with open(os.path.join(self.output_dir_root, filename), 'w', encoding='utf8') as output_file: with open(os.path.join(self.output_dir_root, filename), 'w', encoding='utf8') as output_file:
output_file.write(html_output) output_file.write(html_output)
@ -73,7 +77,8 @@ class Website:
md_content = ''.join(parts[2:]) md_content = ''.join(parts[2:])
md_content = re.sub(r'\(([^)]+)\)\[([^\]]+)\]', r'<a href="\2">\1</a>', md_content) md_content = re.sub(r'\(([^)]+)\)\[([^\]]+)\]', r'<a href="\2">\1</a>', md_content)
html_content = markdown.markdown(md_content) html_content = markdown.markdown(md_content)
return metadata, html_content about_modified_time = time.ctime(os.fstat(f.fileno()).st_mtime)
return metadata, html_content, about_modified_time
def create_list(self): def create_list(self):
template = self.env.get_template('list.html') template = self.env.get_template('list.html')
@ -96,7 +101,8 @@ class Website:
template = self.env.get_template('about.html') template = self.env.get_template('about.html')
html_output = template.render( html_output = template.render(
content=self.about_content, content=self.about_content,
socials=self.about_meta socials=self.about_meta,
modified_time = self.about_modified_time
) )
with open(os.path.join('public', 'about.html'), 'w', encoding='utf8') as output_file: with open(os.path.join('public', 'about.html'), 'w', encoding='utf8') as output_file:
output_file.write(html_output) output_file.write(html_output)
@ -138,12 +144,13 @@ class Website:
with open(json_file, 'w', encoding='utf8') as f: with open(json_file, 'w', encoding='utf8') as f:
json.dump(page_info_list, f, ensure_ascii=False, indent=4) json.dump(page_info_list, f, ensure_ascii=False, indent=4)
class Page: class Page:
def __init__(self, metadata, md_content, filename): def __init__(self, metadata, md_content, filename, last_updated):
self.metadata = metadata self.metadata = metadata
self.content = md_content self.content = md_content
self.filename = filename self.filename = filename
self.last_updated = last_updated
self.title = self.metadata['title'] self.title = self.metadata['title']
self.type = self.metadata['type'] self.type = self.metadata['type']
self.year = self.metadata['year'] self.year = self.metadata['year']
@ -185,6 +192,13 @@ class Page:
def display_metadata(self): def display_metadata(self):
output = f"Title: {self.title}\nYear: {self.year}\nDate: {self.date}\nTags: {self.tags}\nType: {self.type}" output = f"Title: {self.title}\nYear: {self.year}\nDate: {self.date}\nTags: {self.tags}\nType: {self.type}"
print(output) print(output)
def get_modified_time_readable(self):
if self.last_updated is not None:
last_modified_time = self.last_updated.st_mtime
last_modified_time_readable = time.ctime(last_modified_time)
return last_modified_time_readable
return None
def main(): def main():
inst = Website('templates', 'public') inst = Website('templates', 'public')

10
public/about.html

@ -38,6 +38,15 @@
<div>git <a href="https://git.fioruil.ie/" target="_blank"></a></div> <div>git <a href="https://git.fioruil.ie/" target="_blank"></a></div>
</div> </div>
<div id="wanderers-container">
<h4>Wanderers: </h4>
<p id="wander-count"></p>
</div>
<div id="modified-time">
<h4>Last Modified: </h4>
<p> Thu Jun 20 17:36:45 2024</p>
</div>
</div> </div>
</div> </div>
<a><span id="monster"> <a><span id="monster">
@ -48,6 +57,7 @@
</a> </a>
</div> </div>
<script src="js/mob.js"></script> <script src="js/mob.js"></script>
<script src="js/wander.js"></script>
</div> </div>
</body> </body>

11
public/articles/(o)machine.html

@ -47,7 +47,7 @@
<div id="showcase-cont"> <div id="showcase-cont">
<div class="showcase"> <div class="showcase">
<p>(2026)</p> <p>(2022)</p>
<p>Speak It Now Eat It, Revision Performing Arts Festival,</p> <p>Speak It Now Eat It, Revision Performing Arts Festival,</p>
<p>Belfast</p> <p>Belfast</p>
</div> </div>
@ -73,9 +73,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Fri Jun 21 09:27:25 2024</p>
</div>
</div> </div>
</div> </div>

9
public/articles/ai-x-body.html

@ -46,9 +46,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Thu Jun 20 17:23:18 2024</p>
</div>
</div> </div>
</div> </div>

9
public/articles/beauty-and-the-beep.html

@ -88,9 +88,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Sat Jun 8 22:14:44 2024</p>
</div>
</div> </div>
</div> </div>

9
public/articles/data.html

@ -86,9 +86,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Sat Jun 8 23:33:47 2024</p>
</div>
</div> </div>
</div> </div>

9
public/articles/demo.html

@ -87,9 +87,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Thu Jun 20 18:00:30 2024</p>
</div>
</div> </div>
</div> </div>

9
public/articles/dwelling.html

@ -79,9 +79,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Sat Jun 8 23:36:42 2024</p>
</div>
</div> </div>
</div> </div>

9
public/articles/electronic-image.html

@ -82,9 +82,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Sun Jun 9 00:02:18 2024</p>
</div>
</div> </div>
</div> </div>

9
public/articles/latent-mirror.html

@ -82,9 +82,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Sat Jun 8 23:39:31 2024</p>
</div>
</div> </div>
</div> </div>

9
public/articles/undefined.html

@ -79,9 +79,12 @@
<div id="sleeping-mario">
<img src="/images/website/mario-sleep-up.gif"> <div id="modified-time">
</div> <h4>Last Modified: </h4>
<p> Sat Jun 8 23:41:06 2024</p>
</div>
</div> </div>
</div> </div>

36
public/css/styles.css

@ -476,6 +476,42 @@ body {
margin: 0; margin: 0;
} }
#modified-time {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
margin-top: 25px;
}
#modified-time p{
padding: 0;
margin: 0;
}
#modified-time h4{
padding: 0;
margin: 0;
}
#wanderers-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
margin-top: 25px;
}
#wanderers-container p{
padding: 0;
margin: 0;
}
#wanderers-container h4{
padding: 0;
margin: 0;
}

9
public/js/wander.js

@ -0,0 +1,9 @@
function GetWanderCount(){
let element = document.getElementById('wander-count')
fetch('../json/counter.json')
.then((response) => response.json())
.then((json) => element.innerHTML = json['count']);
}
GetWanderCount()

99
server.js

@ -1,6 +1,6 @@
const express = require('express'); const express = require('express');
const path = require('path'); const path = require('path');
const fs = require('fs') const fs = require('fs');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
const crypto = require('crypto'); const crypto = require('crypto');
const { exec } = require('child_process'); const { exec } = require('child_process');
@ -8,37 +8,38 @@ require('dotenv').config();
const app = express(); const app = express();
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
const GITEA_SECRET = process.env.GITEA_SECRET const GITEA_SECRET = process.env.GITEA_SECRET;
const counterFilePath = path.join(__dirname, 'public/json/counter.json'); const counterFilePath = path.join(__dirname, 'public/json/counter.json');
function readCounter() { function readCounter() {
const data = fs.readFileSync(counterFilePath) const data = fs.readFileSync(counterFilePath);
return JSON.parse(data).count; return JSON.parse(data).count;
} }
function writeCounter(count) { function writeCounter(count) {
const data = JSON.stringify({ count: count}, null, 2) const data = JSON.stringify({ count: count }, null, 2);
fs.writeFileSync(counterFilePath, data) fs.writeFileSync(counterFilePath, data);
} }
// Serve static files from the 'public' directory function IncrementCounter() {
app.use(express.static(path.join(__dirname, 'public'))); let count = readCounter();
count++;
writeCounter(count);
console.log(count);
}
// Middleware to capture raw body // Middleware to capture raw body
app.use(bodyParser.json({ app.use(bodyParser.json({
verify: (req, res, buf, encoding) => { verify: (req, res, buf, encoding) => {
req.rawBody = buf.toString(encoding || 'utf8'); req.rawBody = buf.toString(encoding || 'utf8');
} }
})); }));
// Custom middleware to handle URLs without .html for specific routes // Custom middleware to handle URLs without .html for specific routes
app.use((req, res, next) => { app.use((req, res, next) => {
const urlPath = req.path.split('?')[0]; const urlPath = req.path.split('?')[0];
const htmlRoutes = ['/about', '/list', '/gallery']; const htmlRoutes = ['/about', '/list', '/gallery'];
let count = readCounter()
count++;
writeCounter(count)
console.log(count)
if (htmlRoutes.includes(urlPath)) { if (htmlRoutes.includes(urlPath)) {
req.url += '.html'; req.url += '.html';
} }
@ -48,60 +49,65 @@ app.use((req, res, next) => {
// Route to serve the index.html file // Route to serve the index.html file
app.get('/', (req, res) => { app.get('/', (req, res) => {
IncrementCounter()
res.sendFile(path.join(__dirname, 'public', 'index.html')); res.sendFile(path.join(__dirname, 'public', 'index.html'));
}); });
// Routes to serve the HTML files without .html extension // Routes to serve the HTML files without .html extension
app.get('/about.html', (req, res) => { app.get('/about.html', (req, res) => {
IncrementCounter();
res.sendFile(path.join(__dirname, 'public', 'about.html')); res.sendFile(path.join(__dirname, 'public', 'about.html'));
}); });
app.get('/list.html', (req, res) => { app.get('/list.html', (req, res) => {
IncrementCounter();
res.sendFile(path.join(__dirname, 'public', 'list.html')); res.sendFile(path.join(__dirname, 'public', 'list.html'));
}); });
app.get('/gallery.html', (req, res) => { app.get('/gallery.html', (req, res) => {
IncrementCounter();
res.sendFile(path.join(__dirname, 'public', 'gallery.html')); res.sendFile(path.join(__dirname, 'public', 'gallery.html'));
}); });
// Serve articles without .html extension // Serve articles without .html extension
app.get('/articles/:articleName', (req, res) => { app.get('/articles/:articleName', (req, res) => {
const articleName = req.params.articleName; const articleName = req.params.articleName;
IncrementCounter();
res.sendFile(path.join(__dirname, 'public/articles', `${articleName}.html`)); res.sendFile(path.join(__dirname, 'public/articles', `${articleName}.html`));
}); });
// Webhook handler // Webhook handler
app.post('/api', (req, res) => { app.post('/api', (req, res) => {
const signature = req.headers['x-gitea-signature']; const signature = req.headers['x-gitea-signature'];
const payload = req.rawBody; const payload = req.rawBody;
if (!signature || !payload) { if (!signature || !payload) {
return res.status(400).send('Invalid payload or missing signature'); return res.status(400).send('Invalid payload or missing signature');
} }
// Verify the secret // Verify the secret
const hmac = crypto.createHmac('sha256', GITEA_SECRET); const hmac = crypto.createHmac('sha256', GITEA_SECRET);
const digest = hmac.update(payload).digest('hex'); const digest = hmac.update(payload).digest('hex');
const bufferSignature = Buffer.from(signature, 'hex'); const bufferSignature = Buffer.from(signature, 'hex');
const bufferDigest = Buffer.from(digest, 'hex'); const bufferDigest = Buffer.from(digest, 'hex');
console.log(bufferSignature.length, bufferDigest.length) console.log(bufferSignature.length, bufferDigest.length);
if (bufferSignature.length === bufferDigest.length && crypto.timingSafeEqual(bufferSignature, bufferDigest)) { if (bufferSignature.length === bufferDigest.length && crypto.timingSafeEqual(bufferSignature, bufferDigest)) {
// Secret is valid, update the repository // Secret is valid, update the repository
res.status(200).send('Repository updated successfully'); res.status(200).send('Repository updated successfully');
// Optionally, execute a shell command to pull the latest changes // Optionally, execute a shell command to pull the latest changes
exec('git pull', (error, stdout, stderr) => { exec('git pull', (error, stdout, stderr) => {
if (error) { if (error) {
console.error(`exec error: ${error}`); console.error(`exec error: ${error}`);
return; return;
} }
console.log(`stdout: ${stdout}`); console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`); console.error(`stderr: ${stderr}`);
}); });
} else { } else {
res.status(401).send('Invalid secret'); res.status(401).send('Invalid secret');
} }
}); });
// Error handling // Error handling
@ -110,6 +116,9 @@ app.use((err, req, res, next) => {
res.status(500).send('Something broke!'); res.status(500).send('Something broke!');
}); });
// Serve static files from the 'public' directory
app.use(express.static(path.join(__dirname, 'public')));
// Start the server // Start the server
app.listen(PORT, (err) => { app.listen(PORT, (err) => {
if (err) { if (err) {

5
templates/_modified.html

@ -0,0 +1,5 @@
<div id="modified-time">
<h4>Last Modified: </h4>
<p> {{ modified_time }}</p>
</div>

4
templates/_wanderers.html

@ -0,0 +1,4 @@
<div id="wanderers-container">
<h4>Wanderers: </h4>
<p id="wander-count"></p>
</div>

3
templates/about.html

@ -13,6 +13,8 @@
<div>{{ key }} <a href="{{ value }}" target="_blank"></a></div> <div>{{ key }} <a href="{{ value }}" target="_blank"></a></div>
{% endfor %} {% endfor %}
</div> </div>
{% include '_wanderers.html' %}
{% include '_modified.html' %}
</div> </div>
</div> </div>
<a><span id="monster"> <a><span id="monster">
@ -23,4 +25,5 @@
</a> </a>
</div> </div>
<script src="js/mob.js"></script> <script src="js/mob.js"></script>
<script src="js/wander.js"></script>
{% endblock %} {% endblock %}

5
templates/article.html

@ -57,9 +57,8 @@
</div> </div>
{% endif %} {% endif %}
<div id="sleeping-mario"> {% include '_modified.html' %}
<img src="/images/website/mario-sleep-up.gif">
</div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

Loading…
Cancel
Save