Compare commits

...

14 Commits

Author SHA1 Message Date
53cd3852aa update
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 6m29s
2025-08-27 21:53:25 +01:00
f67f377be1 new images 2025-08-23 16:10:25 +01:00
bfb1b8a21e sitemap
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 3m59s
2025-08-13 22:54:24 +01:00
ef459d728a update link
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 3m16s
2025-08-10 19:53:31 +01:00
5690bcadf9 I fkin found em
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 4m21s
2025-08-08 20:31:55 +01:00
8b5b80f7c5 Merge remote-tracking branch 'refs/remotes/gitea/main'
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 3m7s
2025-08-07 21:26:35 +01:00
66806ad922 events 2025-08-07 21:25:10 +01:00
b29a61a44b fix name box
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 3m2s
2025-08-07 11:28:24 +00:00
a0562330a3 more updates
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 2m59s
2025-08-06 22:39:06 +01:00
df59a2c097 fix typos and css
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 2m31s
2025-08-06 01:33:56 +01:00
8209f52fa7 update og image
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 2m19s
2025-08-06 01:15:44 +01:00
b029eba456 fix
All checks were successful
Build and push container image / build-and-push-image (push) Successful in 2m27s
2025-08-06 00:54:30 +01:00
1b2425a493 toaster update :3
Some checks failed
Build and push container image / build-and-push-image (push) Failing after 5m28s
2025-08-06 00:41:26 +01:00
e66f7e0588 update 2025-06-28 18:12:09 +01:00
66 changed files with 476 additions and 6195 deletions

View File

@@ -0,0 +1,33 @@
name: Build and push container image
run-name: ${{ gitea.actor }} is building and pushing container image
on:
push:
branches:
- main
env:
GITEA_DOMAIN: git.alfieking.dev
GITEA_REGISTRY_USER: acetheking987
RESULT_IMAGE_NAME: acetheking987/alfieking.dev
jobs:
build-and-push-image:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ env.GITEA_DOMAIN }}
username: ${{ env.GITEA_REGISTRY_USER }}
password: ${{ secrets.CONTAINER_REGISTRY_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v6
with:
push: true
tags: ${{ env.GITEA_DOMAIN }}/${{ env.RESULT_IMAGE_NAME }}:latest

2
.gitignore vendored
View File

@@ -3,3 +3,5 @@
db.sqlite db.sqlite
flask_session flask_session
__pycache__ __pycache__
app.log
.vscode

6061
app.log

File diff suppressed because it is too large Load Diff

BIN
db.sqlite

Binary file not shown.

View File

@@ -18,8 +18,5 @@ COPY static static
# Expose the port the app runs on # Expose the port the app runs on
EXPOSE 5000 EXPOSE 5000
# Set environment variables
ENV FLASK_APP=app.py
# run the application # run the application
ENTRYPOINT [ "gunicorn", "-b", ":5000", "--access-logfile", "-", "--error-logfile", "-", "src.wsgi:app" ] ENTRYPOINT [ "gunicorn", "-b", ":5000", "--access-logfile", "-", "--error-logfile", "-", "src.wsgi:app" ]

View File

@@ -1,3 +1,4 @@
psycopg2-binary
python-dotenv python-dotenv
flask-session flask-session
requests requests

2
run.sh
View File

@@ -2,4 +2,4 @@
[ ! -f .env ] || export $(grep -v '^#' .env | xargs) [ ! -f .env ] || export $(grep -v '^#' .env | xargs)
flask --app src.wsgi --debug run flask --app src.wsgi.py --debug run

View File

@@ -36,7 +36,7 @@ def not_found(error=None):
log.warning("Page not found: %s", error) log.warning("Page not found: %s", error)
scores = snake.get_leaderboard() scores = snake.get_leaderboard()
token = snake.generate_start_token() token = snake.generate_start_token()
return render_template('errors/404.html', scores=scores, token=token), 404 if error is not None else 200 return render_template('errors/404.html', scores=scores, token=token, cap_key=env('CAP_KEY', default='')), 404 if error is not None else 200
# Route for 400 error # Route for 400 error

View File

@@ -1,7 +1,7 @@
# Imports # Imports
from flask import Blueprint, render_template, request, abort, send_from_directory from flask import Blueprint, render_template, request, abort, send_file
from os import getenv as env from os import getenv as env
import logging import logging, os
# Create blueprint # Create blueprint
@@ -23,22 +23,43 @@ def index():
return render_template('index.html') return render_template('index.html')
# Route for robots.txt, sitemap.xml, and favicon.ico # Route for favicon
@bp.route('/robots.txt')
@bp.route('/sitemap.xml')
@bp.route('/favicon.ico') @bp.route('/favicon.ico')
def web_stuffs(): def favicon():
return send_from_directory( return send_file('../static/content/other/favicon.ico')
env('STATIC_FOLDER', default='../static'),
request.path.lstrip('/')
)
# catch-all route for any other static pages (only in root path) # Route for robots.txt
@bp.route('/<string:filename>') @bp.route('/robots.txt')
def static_files(filename): def robots():
try: return send_file('../static/content/other/robots.txt')
return render_template(filename if filename.endswith('.html') else filename + '.html')
# Route for sitemap.xml
@bp.route('/sitemap.xml')
def sitemap():
return send_file('../static/content/other/sitemap.xml')
# Catch-all route for generic pages
@bp.route('/<path:filename>')
def catch_all(filename):
try: return render_template(f'pages/{filename if filename.endswith(".html") else filename + ".html"}')
except Exception as e: except Exception as e:
log.error(f"Error serving static file {filename}: {e}") # If the template is not found, check if it is a directory
abort(404) os_path = os.path.join(bp.template_folder, 'pages', filename)[3:]
if os.path.isdir(os_path):
# walk through the directory and find all files
pages = []
for root, dirs, files_in_dir in os.walk(os_path):
for file in files_in_dir:
pages.append(os.path.relpath(os.path.join(root, file), os_path))
for dir in dirs:
pages.append(os.path.relpath(os.path.join(root, dir), os_path) + '/')
# If it is a directory, render a directory page
if not filename.endswith('/'): filename += '/'
return render_template('bases/directory.html', directory=filename, pages=pages)
# If it is a file, return a 404 error
abort(404, f"Template '{filename}' not found: {e}")

View File

@@ -20,10 +20,17 @@ log = logging.getLogger(__name__)
# Create database instance # Create database instance
db = database.Database(db_name=env('DB_NAME', default='db.sqlite')) db = database.Database(
db.execute('CREATE TABLE IF NOT EXISTS snake_scores (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, score INTEGER)') host=env('DB_HOST', default='localhost'),
port=env('DB_PORT', default=5432),
user=env('DB_USER', default='user'),
password=env('DB_PASSWORD', default='password'),
db_name=env('DB_NAME', default='db_name')
)
db.execute('CREATE TABLE IF NOT EXISTS snake_scores (id SERIAL PRIMARY KEY, name TEXT, score INTEGER)')
db.execute('''CREATE TABLE IF NOT EXISTS snake_tokens ( db.execute('''CREATE TABLE IF NOT EXISTS snake_tokens (
id INTEGER PRIMARY KEY AUTOINCREMENT, id SERIAL PRIMARY KEY,
token TEXT UNIQUE NOT NULL, token TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ip TEXT UNIQUE NOT NULL ip TEXT UNIQUE NOT NULL
@@ -37,7 +44,7 @@ def valid_length(value, min_length=1, max_length=100):
def valid_score(score, game_token): def valid_score(score, game_token):
start_time = db.execute('SELECT created_at FROM snake_tokens WHERE token = ?', (game_token,)).fetchone() start_time = db.execute('SELECT created_at FROM snake_tokens WHERE token = %s', (game_token,)).fetchone()
if not start_time: if not start_time:
log.error("Game token not found.") log.error("Game token not found.")
return False return False
@@ -46,7 +53,7 @@ def valid_score(score, game_token):
current_time = datetime.datetime.now() current_time = datetime.datetime.now()
elapsed_time = (current_time - start_time).total_seconds() elapsed_time = (current_time - start_time).total_seconds()
if elapsed_time < score / 10 * 5 + 15: # assuming that each point takes 3 seconds to achieve and 15 seconds to start the game and do captcha if elapsed_time < score / 10 * 3 + 10: # assuming that each point takes 3 seconds to achieve and 10 seconds to start the game and do captcha
log.error("Score is too high for the elapsed time.") log.error("Score is too high for the elapsed time.")
return False return False
@@ -59,7 +66,7 @@ def valid_score(score, game_token):
return False return False
# delete the token after score validation # delete the token after score validation
db.execute('DELETE FROM snake_tokens WHERE token = ?', (game_token,)) db.execute('DELETE FROM snake_tokens WHERE token = %s', (game_token,))
log.info(f"Score {score} validated successfully for token {game_token}.") log.info(f"Score {score} validated successfully for token {game_token}.")
return True return True
@@ -90,8 +97,8 @@ def submit_score():
abort(400, "Score not vilid, so either you are trying to cheat the leaderboard or something is seriously wrong.") abort(400, "Score not vilid, so either you are trying to cheat the leaderboard or something is seriously wrong.")
try: try:
db.execute('INSERT INTO snake_scores (name, score) VALUES (?, ?)', (name, int(score))) db.execute('INSERT INTO snake_scores (name, score) VALUES (%s, %s)', (name, int(score)))
db.execute('DELETE FROM snake_tokens WHERE token = ?', (game_token,)) db.execute('DELETE FROM snake_tokens WHERE token = %s', (game_token,))
log.info(f"Score submitted: {name} - {score}") log.info(f"Score submitted: {name} - {score}")
return redirect('/404') return redirect('/404')
@@ -106,13 +113,13 @@ def generate_start_token():
token = urandom(16).hex() token = urandom(16).hex()
ip = request.headers.get('X-Forwarded-For', request.remote_addr) ip = request.headers.get('X-Forwarded-For', request.remote_addr)
ip_token = db.execute('SELECT token FROM snake_tokens WHERE ip = ?', (ip,)).fetchone() ip_token = db.execute('SELECT token FROM snake_tokens WHERE ip = %s', (ip,)).fetchone()
if ip_token: if ip_token:
log.info(f"Token already exists for IP: {ip}, reusing token.") log.info(f"Token already exists for IP: {ip}, reusing token.")
return ip_token[0] return ip_token[0]
log.info(f"Generated start token: {token}") log.info(f"Generated start token: {token}")
db.execute('INSERT INTO snake_tokens (token, ip) VALUES (?, ?)', (token, ip)) db.execute('INSERT INTO snake_tokens (token, ip) VALUES (%s, %s)', (token, ip))
return token return token
@@ -134,7 +141,7 @@ def clear_old_tokens():
while True: while True:
try: try:
one_hour_ago = datetime.datetime.now() - datetime.timedelta(hours=1) one_hour_ago = datetime.datetime.now() - datetime.timedelta(hours=1)
db.execute('DELETE FROM snake_tokens WHERE created_at < ?', (one_hour_ago,)) db.execute('DELETE FROM snake_tokens WHERE created_at < %s', (one_hour_ago,))
log.info("Old tokens cleared.") log.info("Old tokens cleared.")
except Exception as e: except Exception as e:
log.error(f"Error clearing old tokens: {e}") log.error(f"Error clearing old tokens: {e}")

View File

@@ -23,7 +23,7 @@ def verify_captcha(token: str) -> bool:
try: try:
response = requests.post( response = requests.post(
env('CAP_VERIFY_URL', default='https://<instance_url>/<key_id>/siteverify'), f"https://cap.alfieking.dev/{env('CAP_KEY', default='')}/siteverify",
json={ json={
'secret': env('CAP_SECRET', default=''), 'secret': env('CAP_SECRET', default=''),
'response': token, 'response': token,

View File

@@ -1,10 +1,15 @@
# Imports # Imports
import sqlite3 import psycopg2
# Database class
class Database: class Database:
def __init__(self, db_name='db.sqlite'): def __init__(self, host, port, user, password, db_name):
self.connection = sqlite3.connect(db_name, check_same_thread=False) self.connection = psycopg2.connect(
host=host,
port=port,
user=user,
password=password,
database=db_name
)
self.cursor = self.connection.cursor() self.cursor = self.connection.cursor()
def execute(self, query, params=None): def execute(self, query, params=None):

View File

@@ -1,5 +1,5 @@
# Imports # Imports
from flask import Flask, request, render_template, send_from_directory, abort from flask import Flask
from flask_session import Session from flask_session import Session
from dotenv import load_dotenv from dotenv import load_dotenv

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

View File

Before

Width:  |  Height:  |  Size: 743 KiB

After

Width:  |  Height:  |  Size: 743 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 240 KiB

View File

@@ -1,6 +1,8 @@
User-agent: * User-agent: *
Allow: / Allow: /
Disallow: /404.html Disallow: /404
Disallow: /500
Disallow: /400
Sitemap: https://alfieking.dev/sitemap.xml Sitemap: https://alfieking.dev/sitemap.xml

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://alfieking.dev/</loc>
</url>
<url>
<loc>https://alfieking.dev/toaster</loc>
</url>
<url>
<loc>https://alfieking.dev/events</loc>
</url>
<url>
<loc>https://alfieking.dev/events/paws-n-pistons</loc>
</url>
<url>
<loc>https://alfieking.dev/events/crittersmk</loc>
</url>
</urlset>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

View File

@@ -1,7 +1,7 @@
@import url('https://fonts.googleapis.com/css2?family=Fredoka:wdth,wght@125,700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Fredoka:wdth,wght@125,700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap');
@font-face { @font-face {
font-family:"Irken"; font-family:"Irken";
src:url("/static/content/Irken-Like-AllCaps.woff") format("woff"); src:url("/static/content/fonts/Irken-Like-AllCaps.woff") format("woff");
font-weight:normal; font-weight:normal;
font-style:normal; font-style:normal;
} }
@@ -227,7 +227,7 @@ main section a {
right: 0; right: 0;
bottom: 0; bottom: 0;
opacity: 0.1; opacity: 0.1;
background-image: url('/static/content/background.png'); background-image: url('/static/content/general_images/background.png');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 50% 0; background-position: 50% 0;
background-size: cover; background-size: cover;
@@ -304,6 +304,10 @@ main section a {
box-sizing: border-box; box-sizing: border-box;
} }
a {
text-decoration: none;
}
@media screen and (max-width: 1000px) { @media screen and (max-width: 1000px) {
body { body {
background-color: var(--background-color); background-color: var(--background-color);

View File

@@ -2,7 +2,6 @@ cap-widget {
--cap-background: var(--secondary-background-color-but-slightly-transparent); --cap-background: var(--secondary-background-color-but-slightly-transparent);
--cap-border-color: var(--secondary-background-color); --cap-border-color: var(--secondary-background-color);
--cap-border-radius: 14px; --cap-border-radius: 14px;
--cap-widget-height: 30px;
--cap-widget-width: 230px; --cap-widget-width: 230px;
--cap-widget-padding: 14px; --cap-widget-padding: 14px;
--cap-gap: 15px; --cap-gap: 15px;

13
static/css/directory.css Normal file
View File

@@ -0,0 +1,13 @@
section#directory ul {
list-style: none;
padding: 0;
margin: 0;
}
section#directory li {
margin: 0.5rem 0;
}
section#directory a:hover {
scale: 1.05;
}

17
static/css/gallery.css Normal file
View File

@@ -0,0 +1,17 @@
.gallery {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 1rem;
}
.gallery img {
max-width: 100%;
height: auto;
border-radius: 10px;
}
.gallery-date {
margin: 1rem 0 .25rem 0;
font-size: 2rem;
}

View File

@@ -4,6 +4,7 @@ ul#toaster-specs {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 2px; gap: 2px;
min-width: 400px;
} }
ul#toaster-specs li { ul#toaster-specs li {
@@ -33,6 +34,35 @@ ul#toaster-specs li {
height: 100%; height: 100%;
} }
.fur-meet-gallery-small {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.fur-meet-gallery-small img {
width: 150px;
height: 150px;
object-fit: cover;
border-radius: 10px;
border: 2px solid var(--secondary-background-color);
}
.fur-meet-gallery-small img:hover {
transform: scale(1.05);
transition: transform 0.2s ease-in-out;
cursor: pointer;
}
#fur-meets {
list-style: none;
padding: 0;
margin: 10px;
display: flex;
flex-direction: column;
gap: 10px;
}
@media screen and (max-width: 740px) { @media screen and (max-width: 740px) {
.flex-row { .flex-row {
flex-direction: column; flex-direction: column;
@@ -46,3 +76,9 @@ ul#toaster-specs li {
width: 100%; width: 100%;
} }
} }
@media screen and (max-width: 690px) {
.flex-col {
flex-direction: column;
}
}

View File

@@ -118,7 +118,7 @@ if (document.getElementById('spotify')) {
// load buttons // load buttons
function loadButtons() { function loadButtons() {
fetch('/static/content/buttons.txt').then(response => { fetch('/static/content/other/buttons.txt').then(response => {
return response.text(); return response.text();
}).then(data => { }).then(data => {
container = document.getElementById('button-collection'); container = document.getElementById('button-collection');

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://www.example.com/index.html</loc>
</url>
</urlset>

View File

@@ -4,18 +4,18 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Alfie's basement{% endblock %}</title> <title>{% block title %}Alfie's basement{% endblock %}</title>
<link rel="icon" href="/static/content/icon.webp"> <link rel="icon" href="/static/content/general_images/icon.webp">
<link rel="stylesheet" href="/static/css/base.css"> <link rel="stylesheet" href="/static/css/base.css">
<meta name="description" content="{% block description %}server backend survivor{% endblock %}"> <meta name="description" content="{% block description %}server backend survivor{% endblock %}">
<meta name="keywords" content="Alfie King, Alfie, King, Alfieking, Alfieking.dev, dev, server"> <meta name="keywords" content="{% block keywords %}Alfie King, Alfie, King, Alfieking, Alfieking.dev, dev, server, developer, backend, selfhost, homelab{% endblock %}">
<meta name="author" content="Alfie King"> <meta name="author" content="Alfie King">
<meta name="robots" content="all"> <meta name="robots" content="all">
<meta name="theme-color" content="#63de90" data-react-helmet="true"> <meta name="theme-color" content="#63de90" data-react-helmet="true">
<meta property="og:site_name" content="Alfieking.dev"> <meta property="og:site_name" content="Alfieking.dev">
<meta property="og:url" content="https://alfieking.dev"> <meta property="og:url" content="https://alfieking.dev/">
<meta property="og:title" content="{{ self.title() }}"> <meta property="og:title" content="{{ self.title() }}">
<meta property="og:description" content="{{ self.description() }}"> <meta property="og:description" content="{{ self.description() }}">
<meta property="og:image" content="/static/content/icon.webp"> <meta property="og:image" content="{% block og_image %}/static/content/general_images/icon.webp{% endblock %}">
{% block head %} {% block head %}
{% endblock %} {% endblock %}
</head> </head>
@@ -28,6 +28,7 @@
<ul> <ul>
<li><a href="/">Home</a></li> <li><a href="/">Home</a></li>
<li><a href="/toaster">Toaster</a></li> <li><a href="/toaster">Toaster</a></li>
<li><a href="/events">Events</a></li>
<li><a href="https://git.alfieking.dev/acetheking987">Gitea</a></li> <li><a href="https://git.alfieking.dev/acetheking987">Gitea</a></li>
<li><a href="https://www.last.fm/user/acetheking987">LastFm</a></li> <li><a href="https://www.last.fm/user/acetheking987">LastFm</a></li>
<li><a href="https://prismic.alfieking.dev">Prismic</a></li> <li><a href="https://prismic.alfieking.dev">Prismic</a></li>
@@ -46,28 +47,29 @@
<section id="buttons"> <section id="buttons">
<h1>BUTTONS</h1> <h1>BUTTONS</h1>
<ul> <ul>
<li><a href="https://dimden.dev/"><img src="https://dimden.dev/services/images/88x31.gif" alt="dimden"></a></li> <li><a href="https://emmixis.net/"><img src="/static/content/buttons/emmixis.gif" alt="emmixis"></a></li>
<li><a href="https://ne0nbandit.neocities.org/"><img src="https://ne0nbandit.github.io/assets/img/btn/mine/nbbanner.png" alt="ne0nbandit"></a></li> <li><a href="https://dimden.dev/"><img src="https://dimden.dev/services/images/88x31.gif" alt="dimden"></a></li><!-- hotlink on purpose -->
<li><a href="https://thinliquid.dev"><img src="https://thinliquid.dev/thnlqd.png" alt="thinliquid"></a></li> <li><a href="https://ne0nbandit.neocities.org/"><img src="/static/content/buttons/ne0nbandit.png" alt="ne0nbandit"></a></li>
<li><a href="https://nekoweb.org/"><img src="https://nekoweb.org/assets/buttons/button6.gif" alt="nekoweb"></a><!-- button by s1nez.nekoweb.org --></li> <li><a href="https://thinliquid.dev"><img src="/static/content/buttons/thnlqd.png" alt="thinliquid"></a></li>
<li><a href="https://s1nez.nekoweb.org/"><img src="https://s1nez.nekoweb.org/BUTTON.gif" alt="s1nez"></a></li> <li><a href="https://nekoweb.org/"><img src="/static/content/buttons/nekoweb.gif" alt="nekoweb"></a><!-- button by s1nez.nekoweb.org --></li>
<li><a href="https://beeps.website"><img src="https://beeps.website/assets/images/88x31-d.gif" alt="beeps"></a></li> <li><a href="https://s1nez.nekoweb.org/"><img src="/static/content/buttons/s1nez.gif" alt="s1nez"></a></li>
<li><a href="https://itsnotstupid.com"><img src="https://itsnotstupid.com/pics/button1.gif" alt="itsnotstupid"></a></li> <li><a href="https://beeps.website"><img src="/static/content/buttons/beeps.gif" alt="beeps"></a></li>
<li><a href='https://blinkies.cafe'><img src='https://blinkies.cafe/b/display/blinkiesCafe-badge.gif' alt='blinkies.cafe | make your own blinkies!'></a></li> <li><a href="https://itsnotstupid.com"><img src="/static/content/buttons/insia.gif" alt="itsnotstupid"></a></li>
<li><a href="https://eightyeightthirty.one"><img src="https://eightyeightthirty.one/88x31.png" alt="88x31"></a></li> <li><a href='https://blinkies.cafe'><img src='/static/content/buttons/blinkiescafe.gif' alt='blinkies.cafe | make your own blinkies!'></a></li>
<li><a href="https://neocities.org"><img src="https://cyber.dabamos.de/88x31/neocities-now.gif" alt="neocities"></a></li> <li><a href="https://eightyeightthirty.one"><img src="/static/content/buttons/8831.png" alt="88x31"></a></li>
<li><a href="https://tuxedodragon.art"><img src="https://tuxedodragon.art/tuxedodragon%2088x31.gif" alt="tuxedodragon"></a></li> <li><a href="https://neocities.org"><img src="/static/content/buttons/neocities.gif" alt="neocities"></a></li>
<li><a href="https://tuxedodragon.art"><img src="/static/content/buttons/tuxedodragon.gif" alt="tuxedodragon"></a></li>
</ul> </ul>
</section> </section>
<section> <section>
<pre class="vsmoltext"> |\ _,,,---,,_<br>ZZZzz /,`.-'`' -. ;-;;,_<br> |,4- ) )-,_. ,\ ( `'-'<br> '---''(_/--' `-'\_)</pre> <pre class="vsmoltext"> |\ _,,,---,,_<br>ZZZzz /,`.-'`' -. ;-;;,_<br> |,4- ) )-,_. ,\ ( `'-'<br> '---''(_/--' `-'\_)</pre>
</section> </section>
<img src="/static/content/haj.gif" alt="haj" class="haj"> <img src="/static/content/general_images/haj.gif" alt="haj" class="haj">
</div> </div>
<main id="main"> <main id="main">
<header id="home"> <header id="home">
<div class="row"> <div class="row">
<img src="/static/content/icon.webp"> <img src="/static/content/general_images/icon.webp">
<div> <div>
<h1>Alfie King</h1> <h1>Alfie King</h1>
<h2 id="typing">server backend survivor</h2> <h2 id="typing">server backend survivor</h2>

View File

@@ -0,0 +1,22 @@
{% extends "bases/base.html" %}
{% block title %}/{{ directory }} - Alfie's basement{% endblock %}
{% block description %}server backend survivor{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/directory.css">
{% endblock %}
{% block scripts %}
{% endblock %}
{% block content %}
<section id="directory">
<h1>/{{ directory }}</h1>
<ul>
{% for page in pages %}
<li><a href="/{{ directory }}{{ page.split('.')[0] }}">{{ page.split('.')[0] }}</a></li>
{% endfor %}
</ul>
</section>
{% endblock %}

View File

@@ -29,8 +29,8 @@
<section class="min-width"> <section class="min-width">
<h2>Submit score</h2> <h2>Submit score</h2>
<form action="/snake/submit" method="POST" id="snakeForm"> <form action="/snake/submit" method="POST" id="snakeForm">
<input type="text" id="name" name="name" placeholder="Your name" required> <input type="text" id="name" name="name" maxlength=15 minlength=3 placeholder="Your name" required>
<cap-widget id="captcha" data-cap-api-endpoint="https://cap.alfieking.dev/57d36430b9cb/api/"></cap-widget> <cap-widget id="captcha" data-cap-api-endpoint="https://cap.alfieking.dev/{{ cap_key }}/"></cap-widget>
<input type="hidden" id="score" name="score" value="0"> <input type="hidden" id="score" name="score" value="0">
<input type="hidden" id="game_token" name="game_token" value="{{ token}}"> <input type="hidden" id="game_token" name="game_token" value="{{ token}}">
<button type="submit" id="submit">Submit</button> <button type="submit" id="submit">Submit</button>

View File

@@ -104,6 +104,16 @@
<h1>Some News</h1> <h1>Some News</h1>
<h6>(dont expect this to be updated often tho :P)</h6> <h6>(dont expect this to be updated often tho :P)</h6>
<ul> <ul>
<li>
<h2>28-06-2025</h2>
<p>
I have updated the site a bit, I have added a few more featues, but the main update is that the site is now using flask as a backend.
I didn't want to use a framework at first, mainly because I like the simplicity of a static site, but it allows me to use templatiing and makes
adding new features easier and more organized. The site is also more interacive now, with a few secrets on some of the pages. I still plan on adding
more secrets and features. I also plan on adding a blog section, that I will move this to, so that I can give updates on the site and other things
that I find interesting.
</p>
</li>
<li> <li>
<h2>18-06-2025</h2> <h2>18-06-2025</h2>
<p> <p>

View File

@@ -0,0 +1,51 @@
{% extends "bases/base.html" %}
{% block title %}Critters MK - Alfie's basement{% endblock %}
{% block description %}furry corner{% endblock %}
{% block og_image %}/static/content/Toaster_v1.0_Dark.png{% endblock %}
{% block keywords %}
Alfie King, Alfie, King, Alfieking, Alfieking.dev, dev, server, developer, backend, selfhost, homelab, furry, protogen, toaster,
fursona, fur, furmeet, fursuit, persona, character, protogen fursona, protogen character, protogen fursona design,
protogen character design, critters mk, critters cmk, paws n pistons, paws'n'pistons, paws n pistons furry meet, paws'n'pistons furry meet,
protogen v1.0, toaster v1.0
{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/gallery.css">
{% endblock %}
{% block content %}
<section>
<h1>Critters MK</h1>
<p>
Critters Mk is a fur meet based in Milton Keynes, UK. They hold a meet once a month on saturdays around the area, usually at local parks. They are a
therian friendly group, and there are a variety of fursuiters and non-fursuiters that attend. The group is very welcoming to newcomers, and the meets
are a great way to meet new people in the furry community. There is also atleast one fursuit maker in the group to my knowledge, so if you are looking
for a fursuit, you may be able to find one there. The group is also very active on Telegram, and they have a Twitter page where they post updates about
the meets.
<br><br>
I have attended a few of the meets, and I enjoyed talking to the people there. I plan on attending every meet I can in the future, as well as any other local events
that I can find. If you are in the area, I highly recommend checking them out. You can find more information about the group on their
<a href="https://x.com/cmkfurmeet" target="_blank">Twitter page</a> (I don't know if I can link their Telegram group :<)
</p>
</section>
<section>
<h1>Photos :3</h1>
<p>
Here are some photos from the meets I have attended. I will add more as I attend more meets.
</p>
<h2 class="gallery-date">26th July 2025</h2>
<div class="gallery">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
</div>
<h2 class="gallery-date">23rd Aug 2025</h2>
<div class="gallery">
<img src="/static/content/fur_meets/23-08-2025_critters_mk/PXL_20250823_130640362.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/23-08-2025_critters_mk/PXL_20250823_130648109.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/23-08-2025_critters_mk/PXL_20250823_130659800.jpg"" alt="Critters MK">
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,64 @@
{% extends "bases/base.html" %}
{% block title %}Paws'N'Pistons - Alfie's basement{% endblock %}
{% block description %}furry corner{% endblock %}
{% block og_image %}/static/content/Toaster_v1.0_Dark.png{% endblock %}
{% block keywords %}
Alfie King, Alfie, King, Alfieking, Alfieking.dev, dev, server, developer, backend, selfhost, homelab, furry, protogen, toaster,
fursona, fur, furmeet, fursuit, persona, character, protogen fursona, protogen character, protogen fursona design,
protogen character design, critters mk, critters cmk, paws n pistons, paws'n'pistons, paws n pistons furry meet, paws'n'pistons furry meet,
protogen v1.0, toaster v1.0
{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/gallery.css">
<style>
#woooooo {
max-width: 50%;
height: auto;
border-radius: 10px;
margin: 10px;
}
@media (max-width: 600px) {
#woooooo {
max-width: 100%;
}
}
</style>
{% endblock %}
{% block content %}
<section>
<h1>Paws'N'Pistons</h1>
<p>
Paws'N'Pistons is a furry car meet that takes place across the UK. They are a very welcoming group that is open to all furries, regardless
of whether you have a car or not. Their meets last all day and involve multiple hours of driving across the country to various locations. They
also have a <a href="https://pawsnpistons.com" target="_blank">shop</a> where you can buy car stickers and other merch. They also hand out free
stickers at their meets. Their main social media is their <a href="https://www.instagram.com/paws_n_pistons/" target="_blank">Instagram</a>, where
they post photos from their meets and updates about upcoming events.
<br><br>
I've only attended one meet on the 3rd of August 2025, and it was a great experience. The people were very chill and I enjoyed driving around with them.
ALSO, one of them offered to let me try their fursuit!!! Im now going to speedrun going broke trying to get a fursuit of my own cus of this :3 (I was
already planning on getting one, but this just made me want one more).
<br>
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_200906329.jpg" alt="me in a fursuit" id="woooooo">
<br>
The fursuit belongs to <a href="https://www.tiktok.com/@trickythefox" target="_blank">Tricky the Fox</a>, they are a very chill person and I had a great time talking to them ^w^.
<h1>Photos :3</h1>
<p>
Here are some photos from the meets I have attended. I will add more as I attend more meets.
</p>
<h2 class="gallery-date">3rd Aug 2025</h2>
<div class="gallery">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_140629639.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141242090.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_182023562.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_184321576.jpg" alt="Paws'N'Pistons">
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,107 @@
{% extends "bases/base.html" %}
{% block title %}Toaster - Alfie's basement{% endblock %}
{% block description %}furry corner{% endblock %}
{% block og_image %}/static/content/Toaster_v1.0_Dark.png{% endblock %}
{% block keywords %}
Alfie King, Alfie, King, Alfieking, Alfieking.dev, dev, server, developer, backend, selfhost, homelab, furry, protogen, toaster,
fursona, fur, furmeet, fursuit, persona, character, protogen fursona, protogen character, protogen fursona design,
protogen character design, critters mk, critters cmk, paws n pistons, paws'n'pistons, paws n pistons furry meet, paws'n'pistons furry meet,
protogen v1.0, toaster v1.0
{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/toaster.css">
{% endblock %}
{% block content %}
<section>
<h1>Toaster</h1>
<p>
heya, you may have guessed by now that I am a furry. Specifically my fursona is a protogen called Toaster. I didn't actually choose the name,
I just couldn't think of a name and a few people just started calling me Toaster because I am a protogen.
<br><br>
Originally (before I was a furry), I had a unnamed charcater that was just saved as "lil_guy.png" in my files. He is the tv head character
that I the main "mascot" of my website, I drew him a while ago when I was planning to make a functional tv head.
<br><br>
Once I eventually got out of the furry closet, I was trying to think of a species to choose and I thought that protogens are a mix of having a
screen for a face and being fluffy, so I thought it would be a good fit. I still want to keep the tv head character in some places since I rly like him,
however I plan on using Toaster more. So he may become the main mascot of my website "soon ish".
</p>
</section>
<div class="flex-row">
<section>
<h1>Specs</h1>
<h6>(Additional specs coming "soon ish", Very subject to change :P)</h6>
<ul id="toaster-specs">
<li><b>Species:</b><span>Protogen</span></li>
<li><b>Version:</b><span>v1.0</span></li>
<li><b>Height:</b><span>1.73m</span></li>
<li><b>Weight:</b><span>Mild Chonk</span></li>
<li><b>Base Color:</b><span class="color" style="background-color: #0e0c11">#0e0c11</span></li>
<li><b>Accent Color:</b><span class="color" style="background-color: #a685c6">#a685c6</span></li>
<li><b>Operating System:</b><span>Proot OS&trade;</span></li>
<li><b>Processor:</b><span>Fried Potato</span></li>
<li><b>RAM:</b><span>Not Enough</span></li>
<li><b>Storage:</b><span>1.44MB Floppy</span></li>
<li><b>Ports:</b><span>USB-C</span></li> <!-- You know exactly where this is dont you :3 (note: this is a joke (probably), there are ports are behind the round screens tho)-->
<li><b>Accessories:</b><span>"Neck Armor"</span></li>
<li><b>Bugs:</b><span>Anxiety<sup>2</sup></span></li>
<li><b>Gender:</b><span>Male</span></li>
</ul>
</section>
<div class="flex-col">
<img src="/static/content/toaster/Toaster_v1.0_Dark.png" alt="toaster" id="toaster-img">
<section class="fill-height">
<p>
NEW AND IMPROVED! Toaster v1.0 is here!
<br><br>
Toaster v1.0 is the first version of Toaster that I have drawn that I am actually happy with.
Im still working on the design, so it may change in the future, but I think I like this enough to keep it for now.
</p>
</section>
</div>
</div>
<section>
<h1>Plans</h1>
<p>
I plan on drawing Toaster "properly" soon, im quite happy with the current design, but I want to add more detail and personality to him.
I also want to make a proper ref sheet for him, so it looks like I have a decent idea of what im doing, cus im kinda winging it right now.
<br><br>
I also wanna try make a fursuit head of Toaster, but I am not sure how well that will go. I can handle the electronics and I know a few people
with 3d printers, so I can get the base printed. However I have never made a fursuit before, so idk how well it will go, expecially with the fur.
I have no clue how to make the fur look good, so I may just end up getting someone else to help me with that. Budget is also a concern, cus im
clinically broke. So rn im working of whatever I can buy from shady chinese websites for electronics and whatever I can find in my local area for the fur.
<br><br>
If I end up making a fursuit, I will probably make a post about it on my site and maybe even make a video of it (but dont hold me to that).
</p>
</section>
<section>
<h1>Events</h1>
<p>
There are a few events that ive been to, however I plan on trying to go to more in the future.
<br>
</p>
<ul id="fur-meets">
<li>
<a href="/events/crittersmk"><b>Critters MK</b></a> - A furmeet in Milton Keynes.
<div class="fur-meet-gallery-small">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
</div>
</li>
<li>
<a href="/events/paws-n-pistons"><b>Paws'N'Pistons</b></a> - A furry car meet around the UK.
<div class="fur-meet-gallery-small">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
</div>
</li>
<p>Click on the links to view more photos from each event :3</p>
</ul>
</section>
{% endblock %}

View File

@@ -1,63 +0,0 @@
{% extends "bases/base.html" %}
{% block title %}Toaster - Alfie's basement{% endblock %}
{% block description %}furry corner{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/toaster.css">
{% endblock %}
{% block content %}
<section>
<h1>Toaster</h1>
<p>
heya, you may have guessed by now that I am a furry. Specifically my fursona is a protogen called Toaster. I didn't actually choose the name,
I just couldn't think of a name and a few people just started calling me Toaster because I am a protogen.
<br><br>
Originally (before I was a furry), I had a unnamed charcater that was just saved as "lil_guy.png" in my files. He is the tv head character
that I the main "mascot" of my website, I drew him a while ago when I was planning to make a functional tv head.
<br><br>
Once I eventually got out of the furry closet, I was trying to think of a species to choose and I thought that protogens are a mix of having a
screen for a face and being fluffy, so I thought it would be a good fit. I still want to keep the tv head character in some places since I rly like him,
however I plan on hopefully drawing Toaster properly soon. Once i do, I may make him the main mascot of my website.
</p>
</section>
<div class="flex-row">
<section>
<h1>Specs</h1>
<h6>(Very subject to change, Im still trying to figure out what I want :P)</h6>
<ul id="toaster-specs">
<li><b>Species:</b><span>Protogen</span></li>
<li><b>Base Color:</b><span class="color" style="background-color: #000">#000000</span></li>
<li><b>Accent Color:</b><span class="color" style="background-color: #8136cd">#8136cd</span></li>
<li><b>Alt Accent Color:</b><span class="color" style="background-color: #1d147c">#1d147c</span></li>
<li><b>Operating System:</b><span>Proot OS&trade;</span></li>
<li><b>Processor:</b><span>Fried Potato</span></li>
<li><b>RAM:</b><span>Not Enough</span></li>
<li><b>Storage:</b><span>1.44MB Floppy</span></li>
</ul>
</section>
<div class="flex-col">
<img src="/static/content/toaster.png" alt="toaster" id="toaster-img">
<section class="fill-height">
<p>
A old image of Toaster, I will draw a new one soon. (Hopefully)
</p>
</section>
</div>
</div>
<section>
<h1>Plans</h1>
<p>
I plan on drawing Toaster properly soon, I have a few ideas for his design but I am not sure what I want to do yet.
I also want to make a proper ref sheet for him, so it looks like I have a decent idea of what im doing, cus im kinda winging it right now.
<br><br>
I also wanna try make a fursuit head of Toaster, but I am not sure how well that will go. I can handle the electronics and I know a few people
with 3d printers, so I can get the base printed. However I have never made a fursuit before, so idk how well it will go, expecially with the fur.
I have no clue how to make the fur look good, so I may just end up getting someone else to help me with that. Budget is also a concern, cus im
clinically broke, rn so Im working of whatever I can buy from shady chinese websites for electronics and whatever I can find in my local area for the fur.
<br><br>
If I end up making a fursuit, I will probably make a post about it on my site and maybe even make a video of it (but dont hold me to that).
</p>
</section>
{% endblock %}