Compare commits

...

26 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
d48dd04af9 snake "security" 2025-06-22 16:07:01 +01:00
f3d5cb9d53 cleaned backend 2025-06-22 15:56:38 +01:00
da447939bb css fixes 2025-06-21 14:03:39 +01:00
968a4cb442 mobile fixes 2025-06-21 02:40:25 +01:00
189d63d7ba toaster 2025-06-21 02:26:24 +01:00
4a577e928a typer fix 2025-06-20 13:32:04 +01:00
e95e424a1e mobile fix 2025-06-20 11:14:03 +01:00
2b6ae9c640 oops 2025-06-20 09:55:20 +01:00
0115328180 Merge pull request 'templated' (#1) from templated into main
Reviewed-on: #1
2025-06-20 08:50:41 +00:00
f2cffc4400 500&404 errors 2025-06-20 09:48:20 +01:00
30884ecaa4 snake 2025-06-20 01:45:09 +01:00
27fbade9f1 udpate 2025-06-18 00:49:31 +01:00
70 changed files with 1950 additions and 628 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

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
.venv
.env
db.sqlite
flask_session
__pycache__
app.log
.vscode

View File

@@ -1,87 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Alfie's basement</title>
<link rel="icon" href="/static/content/icon.webp">
<link rel="stylesheet" href="/static/css/index.css">
<meta name="description" content="Alfie's basement">
<meta name="keywords" content="Alfie King, Alfie, King, Alfieking, Alfieking.dev, dev, server">
<meta name="author" content="Alfie King">
<meta name="robots" content="all">
<meta name="theme-color" content="#63de90" data-react-helmet="true">
<meta property="og:site_name" content="Alfieking.dev">
<meta property="og:url" content="https://alfieking.dev">
<meta property="og:title" content="Alfie's basement">
<meta property="og:description" content="server backend survivor">
<meta property="og:image" content="static/content/icon.webp">
</head>
<body>
<div id="furry"></div>
<div id="sidebar">
<nav>
<section>
<h1>Things to see :3</h1>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/chat">Chat</a></li>
<li><a href="/blog">Blog</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://open.spotify.com/user/xz02oolstlvwxqu1pfcua9exz?si=14396e637f284e03">Spotify</a></li>
<li><a href="https://steamcommunity.com/id/acetheking987/">Steam</a></li>
<li><a href="https://www.youtube.com/@acetheking987">YouTube</a></li>
<li><a href="https://acetheking987.tumblr.com/">Tumblr</a></li>Instagram
<li><a href="https://www.reddit.com/user/acetheking987">Reddit</a></li>
</ul>
</section>
</nav>
<section>
<h6 class="irken">heya, try typing "furry" and "irken" into this page!</h6>
</section>
<section id="buttons">
<h1>BUTTONS</h1>
<ul>
<li><a href="https://dimden.dev/"><img src="https://dimden.dev/services/images/88x31.gif" alt="dimden"></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://thinliquid.dev"><img src="https://thinliquid.dev/thnlqd.png" alt="thinliquid"></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://s1nez.nekoweb.org/"><img src="https://s1nez.nekoweb.org/BUTTON.gif" alt="s1nez"></a></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://sparky.wagging.dev"><img src="https://sparky.wagging.dev/sparkybutton.png" alt="sparkythedogo"></a></li>
<li><a href="https://itsnotstupid.com"><img src="https://itsnotstupid.com/pics/button1.gif" alt="itsnotstupid"></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://eightyeightthirty.one"><img src="https://eightyeightthirty.one/88x31.png" alt="88x31"></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://0x4248.dev"><img src="https://sparky.wagging.dev/Webaddons/button.gif" alt="0x4248"></a></li>
</ul>
</section>
<section>
<pre class="vsmoltext"> |\ _,,,---,,_<br>ZZZzz /,`.-'`' -. ;-;;,_<br> |,4- ) )-,_. ,\ ( `'-'<br> '---''(_/--' `-'\_)</pre>
</section>
<img src="static/content/haj.gif" alt="haj" class="haj">
</div>
<main id="main">
<header id="home">
<div class="row">
<img src="/static/content/icon.webp">
<div>
<h1>Alfie King</h1>
<h2 id="typing">server backend survivor</h2>
</div>
</div>
</header>
<section>
<h1>404</h1>
<p>
It seems like the thing you are looking for is not here :P
<img src="https://http.cat/404" alt="404" style="width: max-content;">
For more information, please visit any page but this one.
</p>
</section>
</div>
</main>
<script src="/static/js/index.js"></script>
</body>
</html>

22
dockerfile Normal file
View File

@@ -0,0 +1,22 @@
FROM python:alpine
# Set the working directory
WORKDIR /app
# Copy the requirements file into the container
COPY requirements.txt .
# Install the required packages
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn
# Copy the rest of the application code into the container
COPY src src
COPY templates templates
COPY static static
# Expose the port the app runs on
EXPOSE 5000
# run the application
ENTRYPOINT [ "gunicorn", "-b", ":5000", "--access-logfile", "-", "--error-logfile", "-", "src.wsgi:app" ]

View File

@@ -1,179 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Alfie's basement</title>
<link rel="icon" href="/static/content/icon.webp">
<link rel="stylesheet" href="/static/css/index.css">
<meta name="description" content="Alfie's basement">
<meta name="keywords" content="Alfie King, Alfie, King, Alfieking, Alfieking.dev, dev, server">
<meta name="author" content="Alfie King">
<meta name="robots" content="all">
<meta name="theme-color" content="#63de90" data-react-helmet="true">
<meta property="og:site_name" content="Alfieking.dev">
<meta property="og:url" content="https://alfieking.dev">
<meta property="og:title" content="Alfie's basement">
<meta property="og:description" content="server backend survivor">
<meta property="og:image" content="static/content/icon.webp">
</head>
<body>
<div id="furry"></div>
<div id="sidebar">
<nav>
<section>
<h1>Things to see :3</h1>
<ul>
<li><a href="#Home" onclick="alert('ur already here :3')">Home</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://prismic.alfieking.dev">Prismic</a></li>
<li><a href="https://open.spotify.com/user/xz02oolstlvwxqu1pfcua9exz?si=14396e637f284e03">Spotify</a></li>
<li><a href="https://steamcommunity.com/id/acetheking987/">Steam</a></li>
<li><a href="https://www.youtube.com/@acetheking987">YouTube</a></li>
<li><a href="https://acetheking987.tumblr.com/">Tumblr</a></li>
<li><a href="https://www.reddit.com/user/acetheking987">Reddit</a></li>
</ul>
</section>
</nav>
<section>
<h6 class="irken">heya, try typing "furry" and "irken" into this page!</h6>
</section>
<section id="buttons">
<h1>BUTTONS</h1>
<ul>
<li><a href="https://dimden.dev/"><img src="https://dimden.dev/services/images/88x31.gif" alt="dimden"></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://thinliquid.dev"><img src="https://thinliquid.dev/thnlqd.png" alt="thinliquid"></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://s1nez.nekoweb.org/"><img src="https://s1nez.nekoweb.org/BUTTON.gif" alt="s1nez"></a></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://sparky.wagging.dev"><img src="https://sparky.wagging.dev/sparkybutton.png" alt="sparkythedogo"></a></li>
<li><a href="https://itsnotstupid.com"><img src="https://itsnotstupid.com/pics/button1.gif" alt="itsnotstupid"></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://eightyeightthirty.one"><img src="https://eightyeightthirty.one/88x31.png" alt="88x31"></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://0x4248.dev"><img src="https://sparky.wagging.dev/Webaddons/button.gif" alt="0x4248"></a></li>
</ul>
</section>
<section>
<pre class="vsmoltext"> |\ _,,,---,,_<br>ZZZzz /,`.-'`' -. ;-;;,_<br> |,4- ) )-,_. ,\ ( `'-'<br> '---''(_/--' `-'\_)</pre>
</section>
<img src="static/content/haj.gif" alt="haj" class="haj">
</div>
<main id="main">
<header id="home">
<div class="row">
<img src="/static/content/icon.webp">
<div>
<h1>Alfie King</h1>
<h2 id="typing">server backend survivor</h2>
</div>
</div>
</header>
<nav id="alt-nav">
<ul>
<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://prismic.alfieking.dev">Prismic</a></li>
<li><a href="https://open.spotify.com/user/xz02oolstlvwxqu1pfcua9exz?si=14396e637f284e03">Spotify</a></li>
<li><a href="https://steamcommunity.com/id/acetheking987/">Steam</a></li>
<li><a href="https://www.youtube.com/@acetheking987">YouTube</a></li>
<li><a href="https://acetheking987.tumblr.com/">Tumblr</a></li>
<li><a href="https://www.reddit.com/user/acetheking987">Reddit</a></li>
</ul>
</nav>
<section>
<h1>A lil bit abt me</h1>
<p>
Im not good with writing so dont expect much here. I am a student who is learning c++ and python. I've Done a few projects that i think
are decent enough to show off, so I have put them on this website. I like to mess around with linux and have a few servers that I run. I've
been running a server for a few years now, and I have learned a lot from it. I have also switched to linux on my main computer, which has been
slightly annoying at times (mainly because one of my most played games' anticheat doesn't support on linux atm. Also, the lack of photoshop is
a pain).
<br><br>
I would like to make some more projects in the future, but I am not sure what I want to make yet. I tend to make thing on impulse a lot, and motivation
is "lacking" at times. So the few ideas I do have may never come to fruition. I hope to get better at art so i could hopefully make a game that is somewhat
interesting. But im at a lack of ideas at the moment.
<br><br>
I would also like to have a functional blog on this site, but I bearly talk about much so I dont know what I would write about. I like to ramble on about
random things, but I dont think that would be very interesting to read, and I think that I would forget to update it. I have a tumblr that I have had for a few
years now, but I dont post on it (the social anxiety is too much for me :<). However I hope to get better at that in the future.
</p>
</section>
<section class="blinkies">
<img src="https://adriansblinkiecollection.neocities.org/x45.gif" alt="">
<img src="https://adriansblinkiecollection.neocities.org/t3.gif" alt="">
<img src="https://adriansblinkiecollection.neocities.org/k25.gif" alt="">
<img src="https://s1nez.nekoweb.org/img/52475686_BP77MK3UdnLmIQk.gif" alt="">
<img src="https://s1nez.nekoweb.org/img/hc/hc%20(79).gif" alt="">
<img src="https://dewside.neocities.org/blinkies/bisigns.gif" alt="">
<img src="https://s1nez.nekoweb.org/g/ggg/gg%20(32).gif" alt="">
<img src="https://s1nez.nekoweb.org/img/7dcd20d4.gif" alt="">
</section>
<section class="rowsect">
<a href="" id="spotify-link">
<div id="spotify">
<h1 id="spotify-title"></h1>
<h2 id="spotify-artist"></h2>
</div>
</a>
<div class="stamps">
<img src="https://s1nez.nekoweb.org/img/other/ba4ba47a.png" alt="">
<img src="https://s1nez.nekoweb.org/img/fa02abd7.png" alt="">
<img src="https://s1nez.nekoweb.org/img/hc/hc%20(172).gif" alt="">
<img src="https://gligar.neocities.org/furret2.png" alt="">
<img src="https://gligar.neocities.org/ralsei2.png" alt="">
<img src="https://gligar.neocities.org/tism.png" alt="">
<img src="https://64.media.tumblr.com/11957593416710af9ff049ff6ae7ab63/tumblr_pbb7cd42Ln1xz2nuuo4_100.gif" alt="">
<img src="https://dewside.neocities.org/stamps/dogofwisdom.gif" alt="">
<img src="https://dewside.neocities.org/stamps/kazookid.gif" alt="">
<img src="https://64.media.tumblr.com/3085aeace24ca0c5ddf08aac37cc3ab4/45a30eb92e06a85c-3a/s100x200/b7bfb2e91adbc310f712f4492e668298bd0779de.gif" alt="">
<img src="https://s1nez.nekoweb.org/img/hc/hc%20(27).png" alt="">
<img src="https://s1nez.nekoweb.org/g/ggg/gg%20(13).gif" alt="">
<img src="https://kopawz.neocities.org/stamphoard/stamps2/kriswhere.png" alt="">
<img src="https://adriansblinkiecollection.neocities.org/stamps/g5.gif" alt="">
<img src="https://adriansblinkiecollection.neocities.org/stamps/e40.gif" alt="">
<img src="https://adriansblinkiecollection.neocities.org/stamps/e43.gif" alt="">
</div>
</section>
<section>
<h1>Projects & stuff</h1>
<p>just some projects ive worked on over time</p>
<ul>
<li>
<h2>alfieking.dev</h2>
<p>
This website is a project that I have been working on for a while now. I have made a few versions of it, but I have
never been happy with them. I am quite happy with this version atm since it is more organized and has a design that I
like.
<a href="https://git.alfieking.dev/acetheking987/alfieking.dev">source code</a>
</p>
</li>
<li>
<h2>owo (the terminal command)</h2>
<p>
I made this project as a joke, I can't remember exactly what I baised it off other than the fact that it was somthing
similar to this but in a different language. I originally made it in python, but I have since rewritten it in c++ so
that it would be faster and so that I could learn c++.
<a href="https://git.alfieking.dev/acetheking987/term-owo-cpp">source code</a>
</p>
</li>
<li>
<h2>api.alfieking.dev</h2>
<p>
This is just a basic api that runs the spotify embed on this page. I want it to do other stuff eventually, but atm im
mainly working on the main site and making the server backend better.
</p>
</li>
</ul>
</section>
<section>
<h1>The button collection™</h1>
<div id="button-collection">
</div>
</section>
</main>
<script src="/static/js/index.js"></script>
</body>
</html>

5
requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
psycopg2-binary
python-dotenv
flask-session
requests
flask

5
run.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
[ ! -f .env ] || export $(grep -v '^#' .env | xargs)
flask --app src.wsgi.py --debug run

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

@@ -0,0 +1,48 @@
# Imports
from flask import Blueprint, render_template
from os import getenv as env
import logging
import src.routes.snake as snake
# Create blueprint
bp = Blueprint(
'error_handlers',
__name__,
template_folder=env('TEMPLATE_FOLDER', default='../templates'),
static_folder=env('STATIC_FOLDER', default='../static')
)
# Create logger
log = logging.getLogger(__name__)
# Route for 500 error
@bp.route('/500')
@bp.app_errorhandler(500)
def internal_server_error(error=None):
if error is not None:
log.error("Internal server error: %s", error)
return render_template('errors/500.html'), 500
# Route for 404 error
@bp.route('/404')
@bp.app_errorhandler(404)
def not_found(error=None):
if error is not None:
log.warning("Page not found: %s", error)
scores = snake.get_leaderboard()
token = snake.generate_start_token()
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
@bp.route('/400')
@bp.app_errorhandler(400)
def bad_request(error=None):
if error is not None:
log.warning("Bad request: %s", error)
return render_template('errors/400.html', error=error), 400

65
src/routes/generic.py Normal file
View File

@@ -0,0 +1,65 @@
# Imports
from flask import Blueprint, render_template, request, abort, send_file
from os import getenv as env
import logging, os
# Create blueprint
bp = Blueprint(
'generic',
__name__,
template_folder=env('TEMPLATE_FOLDER', default='../templates'),
static_folder=env('STATIC_FOLDER', default='../static')
)
# Create logger
log = logging.getLogger(__name__)
# Route for index page
@bp.route('/')
def index():
return render_template('index.html')
# Route for favicon
@bp.route('/favicon.ico')
def favicon():
return send_file('../static/content/other/favicon.ico')
# Route for robots.txt
@bp.route('/robots.txt')
def robots():
return send_file('../static/content/other/robots.txt')
# 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:
# If the template is not found, check if it is a directory
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}")

153
src/routes/snake.py Normal file
View File

@@ -0,0 +1,153 @@
# Imports
from flask import Blueprint, abort, request, redirect
from os import urandom, getenv as env
import src.utils.database as database
import src.utils.cap as cap
import logging, datetime, threading, time
# Create blueprint
bp = Blueprint(
'snake',
__name__,
template_folder=env('TEMPLATE_FOLDER', default='../templates'),
static_folder=env('STATIC_FOLDER', default='../static')
)
# Create logger
log = logging.getLogger(__name__)
# Create database instance
db = database.Database(
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 (
id SERIAL PRIMARY KEY,
token TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ip TEXT UNIQUE NOT NULL
)''')
# Input validation function
def valid_length(value, min_length=1, max_length=100):
if not isinstance(value, str):
return False
return min_length <= len(value) <= max_length
def valid_score(score, game_token):
start_time = db.execute('SELECT created_at FROM snake_tokens WHERE token = %s', (game_token,)).fetchone()
if not start_time:
log.error("Game token not found.")
return False
start_time = datetime.datetime.fromisoformat(start_time[0])
current_time = datetime.datetime.now()
elapsed_time = (current_time - start_time).total_seconds()
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.")
return False
if score <= 0 or score > 10000: # Arbitrary upper limit for scores
log.error("Score is out of valid range.")
return False
if score % 10 != 0:
log.error("Score is not a multiple of 10.")
return False
# delete the token after score validation
db.execute('DELETE FROM snake_tokens WHERE token = %s', (game_token,))
log.info(f"Score {score} validated successfully for token {game_token}.")
return True
# Route for score submission
@bp.route('/snake/submit', methods=['POST'])
def submit_score():
name = request.form.get('name')
score = request.form.get('score')
captcha_token = request.form.get('cap-token')
game_token = request.form.get('game_token')
if not cap.verify_captcha(captcha_token):
log.error("Captcha verification failed.")
abort(400, "Captcha verification failed")
if not name or not score or not captcha_token or not game_token:
log.error("Name, score, captcha token, or game token is missing.")
abort(400, "Missing required fields")
if not valid_length(name, min_length=3, max_length=15):
log.error("Invalid name length.")
abort(400, "Name must be between 3 and 15 characters long.")
if not valid_score(int(score), game_token):
log.error("Invalid score.")
abort(400, "Score not vilid, so either you are trying to cheat the leaderboard or something is seriously wrong.")
try:
db.execute('INSERT INTO snake_scores (name, score) VALUES (%s, %s)', (name, int(score)))
db.execute('DELETE FROM snake_tokens WHERE token = %s', (game_token,))
log.info(f"Score submitted: {name} - {score}")
return redirect('/404')
except Exception as e:
log.error(f"Database error: {e}")
abort(500, "Internal server error while submitting score.")
# Generate a unique game token
def generate_start_token():
"""Generate a unique start token for the game."""
token = urandom(16).hex()
ip = request.headers.get('X-Forwarded-For', request.remote_addr)
ip_token = db.execute('SELECT token FROM snake_tokens WHERE ip = %s', (ip,)).fetchone()
if ip_token:
log.info(f"Token already exists for IP: {ip}, reusing token.")
return ip_token[0]
log.info(f"Generated start token: {token}")
db.execute('INSERT INTO snake_tokens (token, ip) VALUES (%s, %s)', (token, ip))
return token
# Get leaderboard scores
def get_leaderboard():
"""Fetch scores from the leaderboard."""
try:
scores = db.execute('SELECT name, score FROM snake_scores ORDER BY score DESC').fetchall()
leaderboard = [{'position': i + 1, 'name': score[0], 'score': score[1]} for i, score in enumerate(scores)]
log.info("Leaderboard fetched successfully.")
return leaderboard
except Exception as e:
log.error(f"Error fetching leaderboard: {e}")
return []
# Clear all tokens older than 1 hour
def clear_old_tokens():
while True:
try:
one_hour_ago = datetime.datetime.now() - datetime.timedelta(hours=1)
db.execute('DELETE FROM snake_tokens WHERE created_at < %s', (one_hour_ago,))
log.info("Old tokens cleared.")
except Exception as e:
log.error(f"Error clearing old tokens: {e}")
time.sleep(3600) # Run every hour
# Start the token clearing thread
token_thread = threading.Thread(target=clear_old_tokens, daemon=True)
token_thread.start()

42
src/utils/cap.py Normal file
View File

@@ -0,0 +1,42 @@
# Imports
from os import getenv as env
import requests, logging
# Create logger
log = logging.getLogger(__name__)
# Function to verify CAPTCHA response
def verify_captcha(token: str) -> bool:
"""
Verify the CAP response token with the CAP server.
Args:
token (str): The CAP response token to verify.
Returns:
bool: True if the token is valid, False otherwise.
"""
if not token:
return False
try:
response = requests.post(
f"https://cap.alfieking.dev/{env('CAP_KEY', default='')}/siteverify",
json={
'secret': env('CAP_SECRET', default=''),
'response': token,
},
timeout=10
)
response.raise_for_status()
if response.status_code != 200:
log.error("CAPTCHA verification failed with status code: %s", response.status_code)
return False
return response.json().get('success', False)
except Exception as e:
log.error("Error verifying CAPTCHA: %s", e)
return False

23
src/utils/database.py Normal file
View File

@@ -0,0 +1,23 @@
# Imports
import psycopg2
class Database:
def __init__(self, host, port, user, password, db_name):
self.connection = psycopg2.connect(
host=host,
port=port,
user=user,
password=password,
database=db_name
)
self.cursor = self.connection.cursor()
def execute(self, query, params=None):
if params is None:
params = []
self.cursor.execute(query, params)
self.connection.commit()
return self.cursor
def close(self):
self.connection.close()

58
src/wsgi.py Normal file
View File

@@ -0,0 +1,58 @@
# Imports
from flask import Flask
from flask_session import Session
from dotenv import load_dotenv
from os import getenv as env, listdir
import logging, importlib
# Load env
load_dotenv()
# Create console log handler
console_log = logging.StreamHandler()
console_log.setFormatter(logging.Formatter("\033[1;32m%(asctime)s\033[0m - \033[1;34m%(levelname)s\033[0m - \033[1;31m%(name)s\033[0m - %(message)s"))
console_log.setLevel(logging.INFO)
# Create file log handler
file_log = logging.FileHandler(env('LOG_FILE', default='app.log'), mode=env('LOG_MODE', default='a'))
file_log.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s"))
file_log.setLevel(logging.DEBUG)
# Add handlers to the logger
log = logging.getLogger()
log.setLevel(logging.DEBUG)
log.addHandler(console_log)
log.addHandler(file_log)
log.info("Logging initialized")
# Create flask app
app = Flask(
__name__,
template_folder=env('TEMPLATE_FOLDER', default='../templates'),
static_folder=env('STATIC_FOLDER', default='../static')
)
# Configure sessions
app.config["SESSION_PERMANENT"] = True
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Load routes
routes_dir = env('ROUTES_DIR', default='src/routes')
for filename in listdir(routes_dir):
if not filename.endswith('.py') and filename.startswith('__'):
continue
module_name = f"{routes_dir.replace('/', '.')}.{filename[:-3]}"
try:
module = importlib.import_module(module_name)
if hasattr(module, 'bp'):
app.register_blueprint(module.bp)
log.info(f"Registered blueprint: {module_name}")
except Exception as e:
log.error(f"Failed to register blueprint {module_name}: {e}")

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

View File

@@ -1,6 +1,8 @@
User-agent: *
Allow: /
Disallow: /404.html
Disallow: /404
Disallow: /500
Disallow: /400
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.

After

Width:  |  Height:  |  Size: 2.7 MiB

3
static/css/400.css Normal file
View File

@@ -0,0 +1,3 @@
section h2 {
margin-top: 2rem !important;
}

155
static/css/404.css Normal file
View File

@@ -0,0 +1,155 @@
#snakeContainer {
padding: 15px;
}
canvas#snakeCanvas {
box-sizing: border-box;
border: 2px solid var(--secondary-background-color);
border-radius: 10px;
width: 100%;
}
form {
display: flex;
flex-direction: column;
width: min-content;
gap: 1rem;
padding: 15px;
}
form input[type="text"] {
padding: 10px;
box-sizing: border-box;
border: 1px solid var(--secondary-background-color);
border-radius: 6px;
background-color: var(--secondary-background-color-but-slightly-transparent);
color: var(--text-color);
}
form button[type="submit"] {
padding: 10px;
box-sizing: border-box;
border: 1px solid var(--secondary-background-color);
border-radius: 6px;
background-color: var(--secondary-background-color-but-slightly-transparent);
color: var(--text-color);
font-weight: bold;
cursor: pointer;
}
.flex-row {
display: flex;
flex-direction: row;
gap: 1rem;
}
.min-width {
width: min-content;
}
.max-width {
width: 100%;
}
#snakeLeaderboardSection {
display: flex;
flex-direction: column;
align-items: center;
padding: 0;
max-height: 272px ;
}
#snakeLeaderboard {
display: flex;
flex-direction: column;
list-style: none;
padding: 0;
margin: 0;
width: 100%;
overflow-y: scroll;
}
#snakeLeaderboard li {
padding: 5px 20px;
background-color: var(--secondary-background-color-but-slightly-transparent);
color: var(--text-color);
font-size: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
#snakeLeaderboard li:nth-child(even) {
background-color: var(--secondary-background-color);
}
dialog {
width: 90%;
max-width: 500px;
padding: 20px;
background-color: var(--background-color);
color: var(--text-color);
border: 2px solid var(--secondary-background-color);
border-radius: 8px;
}
dialog button {
padding: 10px;
width: 100%;
box-sizing: border-box;
border: 2px solid var(--secondary-background-color);
border-radius: 6px;
background-color: var(--secondary-background-color-but-slightly-transparent);
color: var(--text-color);
font-weight: bold;
cursor: pointer;
margin-top: 10px;
}
dialog h2 {
margin: 0;
font-size: 1.5rem;
}
dialog p {
margin: 0;
font-size: 1rem;
}
@media screen and (max-width: 850px) {
.flex-row {
flex-direction: column;
}
form {
align-items: center;
width: 100%;
}
.min-width {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
}
@media screen and (max-width: 650px) {
.mobileOnly {
display: flex;
}
.pcOnly {
display: none;
}
}
@media screen and (min-width: 651px) {
.mobileOnly {
display: none !important;
}
.pcOnly {
display: flex;
}
}

8
static/css/500.css Normal file
View File

@@ -0,0 +1,8 @@
.bluescreen {
background-color: #0077D6;
color: #fff;
padding:40px;
display: flex;
flex-direction: column;
gap: 20px;
}

378
static/css/base.css Normal file
View File

@@ -0,0 +1,378 @@
@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-family:"Irken";
src:url("/static/content/fonts/Irken-Like-AllCaps.woff") format("woff");
font-weight:normal;
font-style:normal;
}
:root {
--primary-color: #5cdd8b;
--primary-color-but-slightly-transparent: #5cdd8b44;
--text-color: #b1b8c0;
--background-color: #020205;
--secondary-background-color: #090914;
--secondary-background-color-but-slightly-transparent: #09091444;
--font-size: 0.5cm;
--font-family: "Space Mono", "serif";
--title-font: 'Roboto Mono', sans-serif;
--irken-font: 'Irken';
}
body {
background-color: var(--background-color);
background-image: url("https://blinkies.cafe/purple-stars-bg.gif");
color: var(--text-color);
font-size: var(--font-size);
font-family: var(--font-family);
display: grid;
grid-template-columns: auto auto;
grid-template-rows: 1fr;
grid-template-areas: "main sidebar";
margin: 7% auto 7% auto;
gap: 1rem;
justify-content: center;
width: 940px;
}
#sidebar {
grid-area: sidebar;
display: flex;
flex-direction: column;
gap: 1rem;
width: 174px;
}
#sidebar section {
backdrop-filter: blur(2px) brightness(0.6);
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
padding: 10px;
}
#sidebar ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
}
#sidebar ul li {
width: fit-content;
}
#sidebar ul li a {
color: var(--text-color);
text-decoration: none;
font-weight: 100;
transition: all 0.2s ease-in-out
}
#sidebar ul li a:hover {
color: var(--primary-color);
font-weight: 900;
}
#sidebar ul li img {
transition: all 0.2s ease-in-out;
}
#sidebar ul li img:hover {
transform: scale(1.1);
}
#sidebar h1 {
font-family: var(--title-font);
font-size: 1.5rem;
font-weight: 900;
margin: 0;
padding: 0;
}
#sidebar h6 {
font-weight: 100;
margin: 0;
padding: 0;
}
#buttons {
text-align: center;
}
#buttons h1 {
font-family: var(--title-font);
font-size: 1.3rem;
font-weight: 900;
margin: 0;
padding: 0;
text-shadow: var(--text-color) 1px 0 10px;
}
#buttons ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
margin-top: 5px;
align-items: center;
}
.vsmoltext {
font-size: 0.5rem;
}
main {
grid-area: main;
width: 761px;
height: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
header {
backdrop-filter: blur(2px) brightness(0.6);
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
padding: 15px;
}
header div.row {
display: flex;
flex-direction: row;
margin: 0;
gap: 1.5rem;
}
header div.column {
display: flex;
flex-direction: column;
justify-content: center;
margin: 0;
}
header img {
width: 9rem;
height: 9rem;
}
header h1 {
font-family: var(--title-font);
font-size: 5rem;
font-weight: 900;
padding: 0;
margin: 0;
}
header h2 {
font-family: var(--title-font);
font-size: 1.75rem;
font-weight: 100;
padding: 0;
margin: 0;
position: relative;
top: -1rem;
}
main section {
backdrop-filter: blur(2px) brightness(0.6);
width: 100%;
display: flex;
flex-direction: column;
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
padding: 15px;
box-sizing: border-box;
}
main section h1 {
font-size: 3rem;
font-weight: 900;
margin: 0;
padding: 0;
}
main section h2 {
font-size: 1.5rem;
font-weight: 900;
margin: 0;
padding: 0;
}
main section h6 {
font-size: 0.7rem;
font-weight: 100;
margin: 0;
padding: 0;
}
main section p {
font-size: 1rem;
margin: 0;
padding: 0;
font-weight: 300;
}
main section a {
color: var(--primary-color);
text-decoration: none;
}
#furry {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
opacity: 0.1;
background-image: url('/static/content/general_images/background.png');
background-repeat: no-repeat;
background-position: 50% 0;
background-size: cover;
z-index: -1;
display: none;
}
.haj {
width: 100%;
filter: drop-shadow(0 0 0.5rem rgb(88, 214, 245));
}
.irken {
font-family: var(--irken-font);
}
#alt-nav {
display: none;
backdrop-filter: blur(2px) brightness(0.6);
width: 100%;
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
padding: 15px;
box-sizing: border-box;
}
#alt-nav ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 1.5rem;
justify-content: center;
}
#alt-nav ul li {
width: fit-content;
}
#alt-nav ul li a {
color: var(--text-color);
text-decoration: none;
font-weight: 100;
transition: all 0.2s ease-in-out
}
#alt-nav ul li a:hover {
color: var(--primary-color);
font-weight: 900;
}
.title-font {
font-family: var(--title-font);
}
.flex-col {
display: flex;
flex-direction: column;
gap: 1rem;
}
.flex-row {
display: flex;
flex-direction: row;
gap: 1rem;
}
.no-sect {
backdrop-filter: none;
border: none;
border-radius: 0;
padding: 0;
box-sizing: border-box;
}
a {
text-decoration: none;
}
@media screen and (max-width: 1000px) {
body {
background-color: var(--background-color);
background-image: url("https://blinkies.cafe/purple-stars-bg.gif");
color: var(--text-color);
font-size: var(--font-size);
font-family: var(--font-family);
display: grid;
grid-template-columns: auto;
grid-template-rows: 1fr;
grid-template-areas: "main";
margin: 7% 0 7% 0;
gap: 1rem;
justify-content: center;
width: 100%;
}
#sidebar {
display: none;
}
#alt-nav {
display: block;
}
main {
width: 100%;
box-sizing: border-box;
padding: 0 1rem 0 1rem;
}
}
@media screen and (max-width: 650px) {
.flex-row {
flex-direction: column;
}
.flex-col {
flex-direction: row;
}
header img {
display: none;
}
header div.row {
justify-content: center;
}
header div {
text-align: center;
}
header h2 {
display: none;
}
div#spotify {
box-sizing: border-box;
background-repeat: no-repeat;
background-size: contain;
height: 100%;
width: auto;
aspect-ratio: 1/1;
display: flex;
flex-direction: column;
}
}

20
static/css/cap.css Normal file
View File

@@ -0,0 +1,20 @@
cap-widget {
--cap-background: var(--secondary-background-color-but-slightly-transparent);
--cap-border-color: var(--secondary-background-color);
--cap-border-radius: 14px;
--cap-widget-width: 230px;
--cap-widget-padding: 14px;
--cap-gap: 15px;
--cap-color: var(--text-color);
--cap-checkbox-size: 25px;
--cap-checkbox-border: 1px solid var(--secondary-background-color);
--cap-checkbox-border-radius: 6px;
--cap-checkbox-background: none;
--cap-checkbox-margin: 2px;
--cap-font: "Space Mono", "serif";
--cap-spinner-color: var(--primary-color);
--cap-spinner-background-color: var(--secondary-background-color-but-slightly-transparent);
--cap-spinner-thickness: 5px;
--cap-credits-font-size: 12px;
--cap-opacity-hover: 0.8;
}

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

@@ -1,233 +1,3 @@
@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-family:"Irken";
src:url("/static/content/Irken-Like-AllCaps.woff") format("woff");
font-weight:normal;
font-style:normal;
}
:root {
--primary-color: #5cdd8b;
--primary-color-but-slightly-transparent: #5cdd8b44;
--text-color: #b1b8c0;
--background-color: #020205;
--secondary-background-color: #090914;
--secondary-background-color-but-slightly-transparent: #09091444;
--font-size: 0.5cm;
--font-family: "Space Mono", "serif";
--title-font: 'Roboto Mono', sans-serif;
--irken-font: 'Irken';
}
body {
background-color: var(--background-color);
background-image: url("https://blinkies.cafe/purple-stars-bg.gif");
color: var(--text-color);
font-size: var(--font-size);
font-family: var(--font-family);
display: grid;
grid-template-columns: auto auto;
grid-template-rows: 1fr;
grid-template-areas: "main sidebar";
margin: 7% auto 7% auto;
gap: 1rem;
justify-content: center;
width: 940px;
}
#sidebar {
grid-area: sidebar;
display: flex;
flex-direction: column;
gap: 1rem;
width: 174px;
}
#sidebar section {
backdrop-filter: blur(2px) brightness(0.6);
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
padding: 10px;
}
#sidebar ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
}
#sidebar ul li {
width: fit-content;
}
#sidebar ul li a {
color: var(--text-color);
text-decoration: none;
font-weight: 100;
transition: all 0.2s ease-in-out
}
#sidebar ul li a:hover {
color: var(--primary-color);
font-weight: 900;
}
#sidebar ul li img {
transition: all 0.2s ease-in-out;
}
#sidebar ul li img:hover {
transform: scale(1.1);
}
#sidebar h1 {
font-family: var(--title-font);
font-size: 1.5rem;
font-weight: 900;
margin: 0;
padding: 0;
}
#sidebar h6 {
font-weight: 100;
margin: 0;
padding: 0;
}
#buttons {
text-align: center;
}
#buttons h1 {
font-family: var(--title-font);
font-size: 1.3rem;
font-weight: 900;
margin: 0;
padding: 0;
text-shadow: var(--text-color) 1px 0 10px;
}
#buttons ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
margin-top: 5px;
align-items: center;
}
.vsmoltext {
font-size: 0.5rem;
}
main {
grid-area: main;
width: 761px;
height: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
header {
backdrop-filter: blur(2px) brightness(0.6);
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
padding: 15px;
}
header div.row {
display: flex;
flex-direction: row;
margin: 0;
gap: 1.5rem;
}
header div.column {
display: flex;
flex-direction: column;
justify-content: center;
margin: 0;
}
header img {
width: 9rem;
height: 9rem;
}
header h1 {
font-family: var(--title-font);
font-size: 5rem;
font-weight: 900;
padding: 0;
margin: 0;
}
header h2 {
font-family: var(--title-font);
font-size: 1.75rem;
font-weight: 100;
padding: 0;
margin: 0;
position: relative;
top: -1rem;
}
main section {
backdrop-filter: blur(2px) brightness(0.6);
width: 100%;
display: flex;
flex-direction: column;
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
padding: 15px;
box-sizing: border-box;
}
main section h1 {
font-size: 3rem;
font-weight: 900;
margin: 0;
padding: 0;
}
main section h2 {
font-size: 1.5rem;
font-weight: 900;
margin: 0;
padding: 0;
}
main section p {
font-size: 1rem;
margin: 0;
padding: 0;
font-weight: 300;
}
main section a {
color: var(--primary-color);
text-decoration: none;
}
#furry {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
opacity: 0.1;
background-image: url('/static/content/background.png');
background-repeat: no-repeat;
background-position: 50% 0;
background-size: cover;
z-index: -1;
display: none;
}
.blinkies {
justify-content: center;
display: flex;
@@ -249,22 +19,6 @@ main section a {
transform: scale(1.1) rotate(-5deg);
}
section.rowsect {
width: 100%;
display: grid;
grid-template-columns: auto auto;
gap: 1rem;
backdrop-filter: none;
border: none;
padding: 0;
}
section.rowsect>div {
backdrop-filter: blur(2px) brightness(0.6);
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
}
.stamps {
display: flex;
flex-direction: row;
@@ -322,15 +76,6 @@ section.rowsect>div {
mix-blend-mode: difference;
}
.haj {
width: 100%;
filter: drop-shadow(0 0 0.5rem rgb(88, 214, 245));
}
.irken {
font-family: var(--irken-font);
}
#button-collection {
display: flex;
flex-direction: row;
@@ -350,93 +95,7 @@ section.rowsect>div {
transform: scale(1.1) rotate(-5deg);
}
#alt-nav {
display: none;
backdrop-filter: blur(2px) brightness(0.6);
width: 100%;
border: var(--secondary-background-color) 2px solid;
border-radius: 10px;
padding: 15px;
box-sizing: border-box;
}
#alt-nav ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 1.5rem;
justify-content: center;
}
#alt-nav ul li {
width: fit-content;
}
#alt-nav ul li a {
color: var(--text-color);
text-decoration: none;
font-weight: 100;
transition: all 0.2s ease-in-out
}
#alt-nav ul li a:hover {
color: var(--primary-color);
font-weight: 900;
}
@media screen and (max-width: 1000px) {
body {
background-color: var(--background-color);
background-image: url("https://blinkies.cafe/purple-stars-bg.gif");
color: var(--text-color);
font-size: var(--font-size);
font-family: var(--font-family);
display: grid;
grid-template-columns: auto;
grid-template-rows: 1fr;
grid-template-areas: "main";
margin: 7% 0 7% 0;
gap: 1rem;
justify-content: center;
width: 100%;
}
#sidebar {
display: none;
}
#alt-nav {
display: block;
}
main {
width: 100%;
box-sizing: border-box;
padding: 0 1rem 0 1rem;
}
}
@media screen and (max-width: 650px) {
header img {
display: none;
}
header div.row {
justify-content: center;
}
section.rowsect {
width: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
backdrop-filter: none;
border: none;
padding: 0;
}
div#spotify {
box-sizing: border-box;
background-repeat: no-repeat;

84
static/css/toaster.css Normal file
View File

@@ -0,0 +1,84 @@
ul#toaster-specs {
padding: 0;
margin: 5px 0;
display: flex;
flex-direction: column;
gap: 2px;
min-width: 400px;
}
ul#toaster-specs li {
display: flex;
justify-content: space-between;
gap: 2rem;
height: 35px;
align-items: center;
}
.color {
border-radius: 10px;
border: 2px solid var(--secondary-background-color);
padding: 1px 5px;
box-sizing: border-box;
height: min-content;
}
#toaster-img {
max-width: 100%;
object-fit: contain;
border-radius: 10px;
border: 2px solid var(--secondary-background-color);
}
.fill-height {
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) {
.flex-row {
flex-direction: column;
}
.flex-col {
flex-direction: row;
}
#toaster-img {
width: 100%;
}
}
@media screen and (max-width: 690px) {
.flex-col {
flex-direction: column;
}
}

View File

@@ -1,5 +1,3 @@
// TYPERWRITER
const values = [
"Web developer",
"Pc games enjoyer",
@@ -22,12 +20,12 @@ const values = [
"Loud Music enjoyer",
"part time femboy :<",
];
var direction = 1;
var text = "";
var speed = 100;
var selectedValue = 0;
var currentValueIndex = 0;
var pause = false;
let typing_direction = 1;
let text = "";
let speed = 100;
let selectedValue = 0;
let currentValueIndex = 0;
let pause = false;
function randomValue() {
selectedValue = Math.floor(Math.random() * values.length);
@@ -35,12 +33,12 @@ function randomValue() {
}
function type() {
if (direction == 1) {
if (typing_direction == 1) {
if (currentValueIndex < values[selectedValue].length) {
text += values[selectedValue][currentValueIndex];
currentValueIndex++;
} else {
direction = -1;
typing_direction = -1;
pause = true;
}
} else {
@@ -48,7 +46,7 @@ function type() {
text = text.slice(0, -1);
currentValueIndex--;
} else {
direction = 1;
typing_direction = 1;
randomValue();
}
}
@@ -57,7 +55,7 @@ function type() {
function typing() {
type();
document.getElementById("typing").innerHTML = "$ " + text;
if (direction == 1) {
if (typing_direction == 1) {
speed = 80 + Math.random() * 100;
} else {
speed = 60 + (Math.random() * 100) / 2;
@@ -74,7 +72,7 @@ typing();
// HIDDEN STUFF (shh don't tell anyone >:3)
var last5Chars = "";
let last5Chars = "";
document.addEventListener('keydown', function(event) {
last5Chars += event.key;
@@ -120,7 +118,7 @@ if (document.getElementById('spotify')) {
// load buttons
function loadButtons() {
fetch('/static/content/buttons.txt').then(response => {
fetch('/static/content/other/buttons.txt').then(response => {
return response.text();
}).then(data => {
container = document.getElementById('button-collection');

174
static/js/snake.js Normal file
View File

@@ -0,0 +1,174 @@
const canvas = document.getElementById('snakeCanvas');
const ctx = canvas.getContext('2d');
const gridSize = 20;
const tileSize = 100;
const snakeSize = 60;
const foodSize = 80;
canvas.width = gridSize * tileSize;
canvas.height = gridSize * tileSize;
let snake = [{ x: 10, y: 10 }, { x: 10, y: 11 }, { x: 10, y: 12 }];
let direction = { x: 0, y: 0 };
let food = { x: Math.floor(Math.random() * gridSize), y: Math.floor(Math.random() * gridSize) };
let score = 0;
let gameOver = false;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw grid of checkerboard pattern
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
ctx.fillStyle = (x + y) % 2 === 0 ?
getComputedStyle(document.documentElement).getPropertyValue('--background-color') :
getComputedStyle(document.documentElement).getPropertyValue('--secondary-background-color');
ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);
}
}
// Draw snake
snake.forEach(segment => {
let nextVec = { x: 0, y: 0 };
// if there is a segment after the current segment
if (snake.indexOf(segment) < snake.length - 1) {
const nextSegment = snake[snake.indexOf(segment) + 1];
nextVec.x = nextSegment.x - segment.x;
nextVec.y = nextSegment.y - segment.y;
}
ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--primary-color');
if (nextVec.x === 0 && nextVec.y === 0) {
ctx.fillRect(
segment.x * tileSize + (tileSize - snakeSize) / 2,
segment.y * tileSize + (tileSize - snakeSize) / 2,
snakeSize,
snakeSize
);
} else if (nextVec.x > 0 || nextVec.y > 0) {
ctx.fillRect(
segment.x * tileSize + (tileSize - snakeSize) / 2,
segment.y * tileSize + (tileSize - snakeSize) / 2,
snakeSize + nextVec.x * (tileSize - snakeSize),
snakeSize + nextVec.y * (tileSize - snakeSize)
);
} else {
ctx.fillRect(
segment.x * tileSize + (tileSize - snakeSize) / 2 + nextVec.x * (tileSize - snakeSize),
segment.y * tileSize + (tileSize - snakeSize) / 2 + nextVec.y * (tileSize - snakeSize),
snakeSize + Math.abs(nextVec.x) * (tileSize - snakeSize),
snakeSize + Math.abs(nextVec.y) * (tileSize - snakeSize)
);
}
});
// Draw food
ctx.fillStyle = '#ff4d4d';
ctx.fillRect(
food.x * tileSize + (tileSize - foodSize) / 2,
food.y * tileSize + (tileSize - foodSize) / 2,
foodSize,
foodSize
);
}
function update() {
if (gameOver) return;
// Move snake
const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
// Add new head
snake.unshift(head);
// Check for food collision
if (head.x === food.x && head.y === food.y) {
score += 10; // Increase score
placeFood();
} else {
snake.pop(); // Remove tail if no food eaten
}
// Check for wall collision
if (head.x < 0 || head.x >= gridSize || head.y < 0 || head.y >= gridSize) {
gameOver = true;
return;
}
// Check for self collision
for (let i = 1; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
gameOver = true;
return;
}
}
}
function placeFood() {
do {
food.x = Math.floor(Math.random() * gridSize);
food.y = Math.floor(Math.random() * gridSize);
} while (snake.some(segment => segment.x === food.x && segment.y === food.y));
}
function changeDirection(event) {
switch (event.key) {
case 'w':
if (direction.y === 0) direction = { x: 0, y: -1 };
break;
case 's':
if (direction.y === 0) direction = { x: 0, y: 1 };
break;
case 'a':
if (direction.x === 0) direction = { x: -1, y: 0 };
break;
case 'd':
if (direction.x === 0) direction = { x: 1, y: 0 };
break;
}
}
// Menu to start the game
function menu() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--background-color');
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.textAlign = 'center';
ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--text-color');
ctx.font = '200px Arial';
ctx.fillText('Snake Game', canvas.width / 2, canvas.height / 2);
ctx.font = '100px Arial';
ctx.fillText('Press W/A/S/D to move', canvas.width / 2, canvas.height / 2 + 100);
ctx.fillText('Click to start', canvas.width / 2, canvas.height / 2 + 200);
canvas.addEventListener('click', startGame);
}
function gameLoop() {
if (!gameOver) {
update();
draw();
setTimeout(gameLoop, 100);
} else {
document.removeEventListener('keydown', changeDirection);
document.getElementById('score').value = score;
alert(`Game Over! Your score: ${score}`);
menu();
}
}
function startGame() {
snake = [{ x: 10, y: 10 }, { x: 10, y: 11 }, { x: 10, y: 12 }];
direction = { x: 1, y: 0 };
food = { x: Math.floor(Math.random() * gridSize), y: Math.floor(Math.random() * gridSize) };
score = 0;
gameOver = false;
canvas.removeEventListener('click', startGame);
document.addEventListener('keydown', changeDirection);
gameLoop();
}
menu();

103
templates/bases/base.html Normal file
View File

@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Alfie's basement{% endblock %}</title>
<link rel="icon" href="/static/content/general_images/icon.webp">
<link rel="stylesheet" href="/static/css/base.css">
<meta name="description" content="{% block description %}server backend survivor{% endblock %}">
<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="robots" content="all">
<meta name="theme-color" content="#63de90" data-react-helmet="true">
<meta property="og:site_name" content="Alfieking.dev">
<meta property="og:url" content="https://alfieking.dev/">
<meta property="og:title" content="{{ self.title() }}">
<meta property="og:description" content="{{ self.description() }}">
<meta property="og:image" content="{% block og_image %}/static/content/general_images/icon.webp{% endblock %}">
{% block head %}
{% endblock %}
</head>
<body>
<div id="furry"></div>
<div id="sidebar">
<nav>
<section>
<h1>Things to see :3</h1>
<ul>
<li><a href="/">Home</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://www.last.fm/user/acetheking987">LastFm</a></li>
<li><a href="https://prismic.alfieking.dev">Prismic</a></li>
<li><a href="https://open.spotify.com/user/xz02oolstlvwxqu1pfcua9exz?si=14396e637f284e03">Spotify</a></li>
<li><a href="https://steamcommunity.com/id/acetheking987/">Steam</a></li>
<li><a href="https://www.youtube.com/@acetheking987">YouTube</a></li>
<li><a href="https://acetheking987.tumblr.com/">Tumblr</a></li>
<li><a href="https://www.reddit.com/user/acetheking987">Reddit</a></li>
<li><a href="/404">404 >:3</a></li>
</ul>
</section>
</nav>
<section>
<h6 class="irken">heya, try typing "furry" and "irken" into this page!</h6>
</section>
<section id="buttons">
<h1>BUTTONS</h1>
<ul>
<li><a href="https://emmixis.net/"><img src="/static/content/buttons/emmixis.gif" alt="emmixis"></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://ne0nbandit.neocities.org/"><img src="/static/content/buttons/ne0nbandit.png" alt="ne0nbandit"></a></li>
<li><a href="https://thinliquid.dev"><img src="/static/content/buttons/thnlqd.png" alt="thinliquid"></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://s1nez.nekoweb.org/"><img src="/static/content/buttons/s1nez.gif" alt="s1nez"></a></li>
<li><a href="https://beeps.website"><img src="/static/content/buttons/beeps.gif" alt="beeps"></a></li>
<li><a href="https://itsnotstupid.com"><img src="/static/content/buttons/insia.gif" alt="itsnotstupid"></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://eightyeightthirty.one"><img src="/static/content/buttons/8831.png" alt="88x31"></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>
</section>
<section>
<pre class="vsmoltext"> |\ _,,,---,,_<br>ZZZzz /,`.-'`' -. ;-;;,_<br> |,4- ) )-,_. ,\ ( `'-'<br> '---''(_/--' `-'\_)</pre>
</section>
<img src="/static/content/general_images/haj.gif" alt="haj" class="haj">
</div>
<main id="main">
<header id="home">
<div class="row">
<img src="/static/content/general_images/icon.webp">
<div>
<h1>Alfie King</h1>
<h2 id="typing">server backend survivor</h2>
</div>
</div>
</header>
<nav id="alt-nav">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/toaster">Toaster</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://prismic.alfieking.dev">Prismic</a></li>
<li><a href="https://open.spotify.com/user/xz02oolstlvwxqu1pfcua9exz?si=14396e637f284e03">Spotify</a></li>
<li><a href="https://steamcommunity.com/id/acetheking987/">Steam</a></li>
<li><a href="https://www.youtube.com/@acetheking987">YouTube</a></li>
<li><a href="https://acetheking987.tumblr.com/">Tumblr</a></li>
<li><a href="https://www.reddit.com/user/acetheking987">Reddit</a></li>
</ul>
</nav>
{% block content %}{% endblock %}
<section>
<footer>
<p>legal stuff idk :3 | icba to &copy; this :P | made with &hearts; and caffine</p>
</footer>
</section>
</main>
{% block scripts %}{% endblock %}
<script src="/static/js/base.js"></script>
</body>
</html>

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 %}

29
templates/errors/400.html Normal file
View File

@@ -0,0 +1,29 @@
{% extends "bases/base.html" %}
{% block title %}400 - Internal Server Error{% endblock %}
{% block description %}Bad request. The server could not understand the request due to invalid syntax.{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/400.css">
{% endblock %}
{% block content %}
<section>
<h1>400 - Bad Request</h1>
<p>
What did you do? The server could not understand the request due to invalid syntax. Please check your request and try again.
</p>
<h2>The fuckup in question</h2>
<p>
{% if error %}
{{ error }}
{% else %}
No specific error message provided.
{% endif %}
</p>
<h2>What to do now</h2>
<p>
idk :P
</p>
</section>
{% endblock %}

82
templates/errors/404.html Normal file
View File

@@ -0,0 +1,82 @@
{% extends "bases/base.html" %}
{% block title %}404 - Not Found{% endblock %}
{% block description %}The page you are looking for does not exist.{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/404.css">
<link rel="stylesheet" href="/static/css/cap.css">
{% endblock %}
{% block content %}
<section>
<h1>404</h1>
<p>
It seems like the thing you are looking for is not here :[
<br><br>
<span class="pcOnly">
while you're here, why not play some snake?
</span>
<span class="mobileOnly">
You can't play snake on mobile, sorry :(
</span>
</p>
<div class="pcOnly" id="snakeContainer">
<canvas id="snakeCanvas"></canvas>
</div>
</section>
<section class="pcOnly flex-row">
<section class="min-width">
<h2>Submit score</h2>
<form action="/snake/submit" method="POST" id="snakeForm">
<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/{{ cap_key }}/"></cap-widget>
<input type="hidden" id="score" name="score" value="0">
<input type="hidden" id="game_token" name="game_token" value="{{ token}}">
<button type="submit" id="submit">Submit</button>
</form>
</section>
<section class="max-width" id="snakeLeaderboardSection">
<h2>Leaderboard</h2>
<ul id="snakeLeaderboard">
{% for score in scores %}
<li>
<span>{{ score.position }}</span>
<span>{{ score.name }}</span>
<span>{{ score.score }}</span>
</li>
{% endfor %}
</ul>
</section>
</section>
<section class="max-width mobileOnly" id="snakeLeaderboardSection">
<h2>Leaderboard</h2>
<ul id="snakeLeaderboard">
{% for score in scores %}
<li>
<span>{{ score.position }}</span>
<span>{{ score.name }}</span>
<span>{{ score.score }}</span>
</li>
{% endfor %}
</ul>
</section>
{% if error %}
<dialog id="errorDialog">
<h2>Error</h2>
<p>{{ error }}</p>
<button onclick="errorDialog.close()">Close</button>
</dialog>
<script>
const errorDialog = document.getElementById('errorDialog');
if (errorDialog) {
errorDialog.showModal();
}
</script>
{% endif %}
{% endblock %}
{% block scripts %}
<script src="/static/js/snake.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@cap.js/widget"></script>
{% endblock %}

17
templates/errors/500.html Normal file
View File

@@ -0,0 +1,17 @@
{% extends "bases/base.html" %}
{% block title %}500 - Internal Server Error{% endblock %}
{% block description %}An unexpected error occurred on the server.{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/500.css">
{% endblock %}
{% block content %}
<section class="bluescreen">
<h1>:(</h1>
<p>
Oopsie Woopsie! Uwu We made a fucky wucky!! A wittle fucko boingo! The code monkeys at our headquarters are working VEWY HAWD to fix this!
</p>
</section>
{% endblock %}

129
templates/index.html Normal file
View File

@@ -0,0 +1,129 @@
{% extends "bases/base.html" %}
{% block title %}Home - Alfie's basement{% endblock %}
{% block description %}server backend survivor{% endblock %}
{% block head %}
<link rel="stylesheet" href="/static/css/index.css">
{% endblock %}
{%block content %}
<section>
<h1>A lil bit abt me</h1>
<p>
Im not good with writing so dont expect much here. I am a student who is learning c++ and python. I've Done a few projects that i think
are decent enough to show off, so I have put them on this website. I like to mess around with linux and have a few servers that I run. I've
been running a server for a few years now, and I have learned a lot from it. I have also switched to linux on my main computer, which has been
slightly annoying at times (mainly because one of my most played games' anticheat doesn't support on linux atm. Also, the lack of photoshop is
a pain).
<br><br>
I would like to make some more projects in the future, but I am not sure what I want to make yet. I tend to make thing on impulse a lot, and motivation
is "lacking" at times. So the few ideas I do have may never come to fruition. I hope to get better at art so i could hopefully make a game that is somewhat
interesting. But im at a lack of ideas at the moment.
<br><br>
I would also like to have a functional blog on this site, but I bearly talk about much so I dont know what I would write about. I like to ramble on about
random things, but I dont think that would be very interesting to read, and I think that I would forget to update it. I have a tumblr that I have had for a few
years now, but I dont post on it (the social anxiety is too much for me :<). However I hope to get better at that in the future.
</p>
</section>
<section class="blinkies">
<img src="https://adriansblinkiecollection.neocities.org/x45.gif" alt="">
<img src="https://adriansblinkiecollection.neocities.org/t3.gif" alt="">
<img src="https://adriansblinkiecollection.neocities.org/k25.gif" alt="">
<img src="https://s1nez.nekoweb.org/img/52475686_BP77MK3UdnLmIQk.gif" alt="">
<img src="https://s1nez.nekoweb.org/img/hc/hc%20(79).gif" alt="">
<img src="https://dewside.neocities.org/blinkies/bisigns.gif" alt="">
<img src="https://s1nez.nekoweb.org/g/ggg/gg%20(32).gif" alt="">
<img src="https://s1nez.nekoweb.org/img/7dcd20d4.gif" alt="">
</section>
<div class="flex-row">
<a href="" id="spotify-link">
<div id="spotify">
<h1 id="spotify-title"></h1>
<h2 id="spotify-artist"></h2>
</div>
</a>
<section class="stamps">
<img src="https://s1nez.nekoweb.org/img/other/ba4ba47a.png" alt="">
<img src="https://s1nez.nekoweb.org/img/fa02abd7.png" alt="">
<img src="https://s1nez.nekoweb.org/img/hc/hc%20(172).gif" alt="">
<img src="https://gligar.neocities.org/furret2.png" alt="">
<img src="https://gligar.neocities.org/ralsei2.png" alt="">
<img src="https://gligar.neocities.org/tism.png" alt="">
<img src="https://64.media.tumblr.com/11957593416710af9ff049ff6ae7ab63/tumblr_pbb7cd42Ln1xz2nuuo4_100.gif" alt="">
<img src="https://dewside.neocities.org/stamps/dogofwisdom.gif" alt="">
<img src="https://dewside.neocities.org/stamps/kazookid.gif" alt="">
<img src="https://64.media.tumblr.com/3085aeace24ca0c5ddf08aac37cc3ab4/45a30eb92e06a85c-3a/s100x200/b7bfb2e91adbc310f712f4492e668298bd0779de.gif" alt="">
<img src="https://s1nez.nekoweb.org/img/hc/hc%20(27).png" alt="">
<img src="https://s1nez.nekoweb.org/g/ggg/gg%20(13).gif" alt="">
<img src="https://kopawz.neocities.org/stamphoard/stamps2/kriswhere.png" alt="">
<img src="https://adriansblinkiecollection.neocities.org/stamps/g5.gif" alt="">
<img src="https://adriansblinkiecollection.neocities.org/stamps/e40.gif" alt="">
<img src="https://adriansblinkiecollection.neocities.org/stamps/e43.gif" alt="">
</section>
</div>
<section>
<h1>Projects & stuff</h1>
<p>just some projects ive worked on over time</p>
<ul>
<li>
<h2>alfieking.dev</h2>
<p>
This website is a project that I have been working on for a while now. I have made a few versions of it, but I have
never been happy with them. I am quite happy with this version atm since it is more organized and has a design that I
like.
<a href="https://git.alfieking.dev/acetheking987/alfieking.dev">source code</a>
</p>
</li>
<li>
<h2>owo (the terminal command)</h2>
<p>
I made this project as a joke, I can't remember exactly what I baised it off other than the fact that it was somthing
similar to this but in a different language. I originally made it in python, but I have since rewritten it in c++ so
that it would be faster and so that I could learn c++.
<a href="https://git.alfieking.dev/acetheking987/term-owo-cpp">source code</a>
</p>
</li>
<li>
<h2>prismic</h2>
<p>
Prismic is a basic message board that I made, it was mainly made to learn how to use templating and more backend
web development. it uses flask for the web framework and uses a sqlite database to store the messages. I have thought
about remaking it in c++ since I found a c++ web framework that I would like to try out.
<a href="https://prismic.alfieking.dev">Primic</a> | <a href="https://git.alfieking.dev/acetheking987/prismic">source code</a>
</p>
</li>
</ul>
</section>
<section>
<h1>The button collection™</h1>
<div id="button-collection">
</div>
</section>
<section>
<h1>Some News</h1>
<h6>(dont expect this to be updated often tho :P)</h6>
<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>
<h2>18-06-2025</h2>
<p>
I plan on updating the site soon, I have a few ideas that I want to implement. I want to make it more
interactive and fun to use. I also want to add a blog section so that I can write about random things that I find interesting. I also
want to add a few more projects that I have been working on. Annoyingly I think it would be a good idea to remake this site with some sort of
framework so i can use templating, however this kinda bothers me since I like the simplicity of this site. And prefer to keep it as a static site
that i can just throw at nginx.
</p>
</li>
</ul>
</section>
{% endblock %}

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 %}