Initial commit
This commit is contained in:
commit
9656f3b061
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
ftp_url.txt
|
||||
music/*
|
||||
dist/
|
||||
scripts/__pycache__/
|
22
LICENSE.txt
Normal file
22
LICENSE.txt
Normal file
@ -0,0 +1,22 @@
|
||||
The code & design of this website are under the MIT license.
|
||||
Do not assume anything about the contents of the website itself.
|
||||
|
||||
Copyright (c) 2020 Ryan Fox
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
53
Makefile
Normal file
53
Makefile
Normal file
@ -0,0 +1,53 @@
|
||||
PAGES_IN = $(wildcard pages/*)
|
||||
POSTS_IN = $(wildcard posts/*.md)
|
||||
MUSIC_IN = $(wildcard music/*.mp3)
|
||||
|
||||
PAGES_OUT = $(addprefix dist/,$(notdir $(PAGES_IN:.md=.html)))
|
||||
POSTS_OUT = $(addprefix dist/blog/,$(notdir $(POSTS_IN:.md=.html)))
|
||||
MUSIC_OUT = $(addprefix dist/music/,$(notdir $(MUSIC_IN)))
|
||||
|
||||
POST_LISTS = dist/blog/index.html dist/blog/feed.xml
|
||||
MUSIC_LISTS = dist/music/index.html dist/music/feed.xml
|
||||
|
||||
all: $(PAGES_OUT) $(POSTS_OUT) $(MUSIC_OUT) $(POST_LISTS) $(MUSIC_LISTS)
|
||||
cp -urv static/. dist
|
||||
|
||||
dist/%.html: pages/%.md | dist
|
||||
scripts/template_md.py $< $@
|
||||
|
||||
dist/%.html: pages/%.html | dist
|
||||
cp $< $@
|
||||
|
||||
dist/blog/%.html: posts/%.md | dist/blog
|
||||
scripts/template_md.py $< $@
|
||||
|
||||
dist/music/%.mp3: music/%.mp3 | dist/music
|
||||
cp $< $@
|
||||
|
||||
$(POST_LISTS): $(POSTS_OUT)
|
||||
scripts/gen_blog.py posts $@
|
||||
|
||||
$(MUSIC_LISTS): music.json | $(OUTPUT_MUSIC)
|
||||
scripts/gen_music.py $< $@
|
||||
|
||||
dist/blog:
|
||||
mkdir -p dist/blog
|
||||
|
||||
dist/music:
|
||||
mkdir -p dist/music
|
||||
|
||||
dist:
|
||||
mkdir dist
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
upload: dist
|
||||
lftp -c "set ftp:list-options -a;\
|
||||
set ssl:verify-certificate false;\
|
||||
open '$(shell cat ftp_url.txt)';\
|
||||
lcd dist;\
|
||||
cd public_html;\
|
||||
mirror --reverse"
|
||||
|
||||
clean:
|
||||
rm -rf dist
|
6
README.txt
Normal file
6
README.txt
Normal file
@ -0,0 +1,6 @@
|
||||
flewkey.com
|
||||
|
||||
This repository contains flewkey.com, my personal website.
|
||||
Jekyll was too complicated for me, so I cobbled together some Python scripts.
|
||||
|
||||
Send questions, issues, and patches to flewkey@2a03.party.
|
210
music.json
Normal file
210
music.json
Normal file
@ -0,0 +1,210 @@
|
||||
[
|
||||
{
|
||||
"id": "calm_down",
|
||||
"name": "Calm Down",
|
||||
"description": "This is a bit of a mess, but I like some of the ideas here.",
|
||||
"timestamp": 1588820400
|
||||
},
|
||||
{
|
||||
"id": "larry_the_cow",
|
||||
"name": "Larry the Cow",
|
||||
"description": "I haven't posted any music since May, so here's something I never uploaded.",
|
||||
"timestamp": 1588462200
|
||||
},
|
||||
{
|
||||
"id": "microwave",
|
||||
"name": "Microwave",
|
||||
"description": "This isn't a coherent song, my goal was to have fun.",
|
||||
"timestamp": 1583470800
|
||||
},
|
||||
{
|
||||
"id": "scrap_5",
|
||||
"name": "Scrap #5",
|
||||
"description": "I tried Ardour for the first time. It's fun.",
|
||||
"group": "Scraps",
|
||||
"timestamp": 1582677000
|
||||
},
|
||||
{
|
||||
"id": "scrap_4",
|
||||
"name": "Scrap #4",
|
||||
"description": "I tried publishing this without Windows this time.",
|
||||
"group": "Scraps",
|
||||
"timestamp": 1582509600
|
||||
},
|
||||
{
|
||||
"id": "scrap_3",
|
||||
"name": "Scrap #3",
|
||||
"description": "I thought this sounded neat.",
|
||||
"group": "Scraps",
|
||||
"timestamp": 1580418000
|
||||
},
|
||||
{
|
||||
"id": "scrap_2",
|
||||
"name": "Scrap #2",
|
||||
"description": "Another scrapped idea.",
|
||||
"group": "Scraps",
|
||||
"timestamp": 1578792600
|
||||
},
|
||||
{
|
||||
"id": "baby_steps",
|
||||
"name": "Baby Steps",
|
||||
"description": "I tried using Ableton to edit a song, and I think it went well.",
|
||||
"timestamp": 1575594000
|
||||
},
|
||||
{
|
||||
"id": "cold_spoon",
|
||||
"name": "Cold Spoon",
|
||||
"description": "I pulled this out of my unfinished folder. Very loopy.",
|
||||
"timestamp": 1574973000
|
||||
},
|
||||
{
|
||||
"id": "feeling_chaotic",
|
||||
"name": "Feeling Chaotic",
|
||||
"description": "I felt like using FamiTracker again, so I did this quickly.",
|
||||
"timestamp": 1573686000
|
||||
},
|
||||
{
|
||||
"id": "scrap_1",
|
||||
"name": "Scrap #1",
|
||||
"description": "I'm going to post \"scraps\" now. These happen when I don't want to finish something I make.",
|
||||
"group": "Scraps",
|
||||
"timestamp": 1565319600
|
||||
},
|
||||
{
|
||||
"id": "seriously_what_the_hell_is_this",
|
||||
"name": "Seriously What The Hell Is This",
|
||||
"description": "Still figuring stuff out. Why do all Ableton instruments sounds weird? Yeah screw this, I'm not making any more.",
|
||||
"timestamp": 1562025600
|
||||
},
|
||||
{
|
||||
"id": "learning_new_software",
|
||||
"name": "Learning New Software",
|
||||
"description": "My first attempt making music outside of a tracker. I spent nearly an hour fighting MuseScore and I have no clue what happened.",
|
||||
"timestamp": 1561939200
|
||||
},
|
||||
{
|
||||
"id": "screw_this",
|
||||
"name": "Screw This!",
|
||||
"description": "FamiSpam failed due to my complete laziness. This is the last song I will upload to the series. Afterwards, I'm probably going to learn proper composition and stop making tracker music for a while.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1560384000
|
||||
},
|
||||
{
|
||||
"id": "puzzle_house",
|
||||
"name": "Puzzle House",
|
||||
"description": "Happy birthday DevEd!",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1558396800
|
||||
},
|
||||
{
|
||||
"id": "shaking_off_rust",
|
||||
"name": "Shaking Off Rust",
|
||||
"description": "I haven't made music for a while. Most of this is terrible, but that won't stop me from publishing it.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1557360000
|
||||
},
|
||||
{
|
||||
"id": "back_into_it",
|
||||
"name": "Back Into It",
|
||||
"description": "Sorry this one sounds awkward, I feel rusty with this. I quit after 12 days last time, so I'll try to beat my previous streak.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1555804800
|
||||
},
|
||||
{
|
||||
"id": "it_gets_better",
|
||||
"name": "It Gets Better",
|
||||
"description": "I was frustrated with this at first.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1554595200
|
||||
},
|
||||
{
|
||||
"id": "boring_and_loopy",
|
||||
"name": "Boring and Loopy",
|
||||
"description": "I tried to make a loopy song, and it turned out terribly. I'll try to do better next time.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1554422400
|
||||
},
|
||||
{
|
||||
"id": "racing_or_something",
|
||||
"name": "Racing or Something",
|
||||
"description": "This is one of my favourite ones so far.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1554249600
|
||||
},
|
||||
{
|
||||
"id": "the_confusing_one",
|
||||
"name": "The Confusing One",
|
||||
"description": "Made in confusion.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1554076800
|
||||
},
|
||||
{
|
||||
"id": "the_first_half_sucks",
|
||||
"name": "The First Half Sucks",
|
||||
"description": "I have no clue how to use arps properly.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1553904000
|
||||
},
|
||||
{
|
||||
"id": "music_box",
|
||||
"name": "Music Box",
|
||||
"description": "I'm not happy with my music, so I've resolved to make 30 seconds of music a day. My goal is to write 20 minutes of music in 2 months.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1553731200
|
||||
},
|
||||
{
|
||||
"id": "laziness",
|
||||
"name": "Laziness.mp3",
|
||||
"description": "I made this for an OHB on Battle of the Bits.",
|
||||
"group": "FamiSpam",
|
||||
"timestamp": 1551207600
|
||||
},
|
||||
{
|
||||
"id": "filthy_foe",
|
||||
"name": "Filthy Foe.nsf",
|
||||
"description": "I made this for an OHB on Battle of the Bits.",
|
||||
"timestamp": 1551193200
|
||||
},
|
||||
{
|
||||
"id": "ohc03815_famitracker_pack_pack_0cc",
|
||||
"name": "OHC03815 famitracker pack pack.0cc",
|
||||
"description": "I made this for an OHB on Battle of the Bits.",
|
||||
"timestamp": 1551171600
|
||||
},
|
||||
{
|
||||
"id": "unsanitary_snow",
|
||||
"name": "Unsanitary Snow",
|
||||
"description": "A track I made for Winter Chip XIV on Battle of the Bits. Hopefully I'll have the time to try participating in OHBs this year.",
|
||||
"timestamp": 1550016000
|
||||
},
|
||||
{
|
||||
"id": "we_give_up",
|
||||
"name": "We Give Up",
|
||||
"description": "Some short FamiTracker songs.",
|
||||
"timestamp": 1547942400
|
||||
},
|
||||
{
|
||||
"id": "running_away",
|
||||
"name": "Running Away",
|
||||
"description": "Some short FamiTracker songs.",
|
||||
"timestamp": 1547942400
|
||||
},
|
||||
{
|
||||
"id": "begin_quest",
|
||||
"name": "Begin Quest",
|
||||
"description": "Some short FamiTracker songs.",
|
||||
"timestamp": 1547942400
|
||||
},
|
||||
{
|
||||
"id": "spooky_sunset",
|
||||
"name": "Spooky Sunset",
|
||||
"description": "Messing around in FamiTracker again.",
|
||||
"timestamp": 1546905600
|
||||
},
|
||||
{
|
||||
"id": "spaceship",
|
||||
"name": "Spaceship",
|
||||
"description": "An old-ish track I wanted to consider finished.",
|
||||
"timestamp": 1532822400
|
||||
}
|
||||
]
|
50
pages/about.md
Normal file
50
pages/about.md
Normal file
@ -0,0 +1,50 @@
|
||||
template: page
|
||||
title: Info
|
||||
license: CC-BY
|
||||
|
||||
# About Me
|
||||
|
||||
Ahoy, my name is Ryan Fox. I am a Canadian guy who likes programming and music.
|
||||
|
||||
I have not done anything to earn online credibility, and you are most likely
|
||||
here because I sent you a link. Despite this, you are spending time reading my
|
||||
website, and I am very grateful for that.
|
||||
|
||||
---
|
||||
|
||||
## Encryption
|
||||
|
||||
These are my PGP and SSH keys. If you would like to encrypt messages, or allow
|
||||
me to access your server, these are the ones to use. I am somewhat confident
|
||||
that they will not get compromised.
|
||||
|
||||
* PGP: [D910C0CAC5BF5739861A4ABD94F56ADFD848851E]({root}pgp.txt)
|
||||
* SSH: [SHA256:IggQMESZIgwIP4/zfYI8ZA1xnMd9g9huOUtgfaKjmCo]({root}ssh.txt)
|
||||
|
||||
---
|
||||
|
||||
## Profiles
|
||||
|
||||
Here is a list of my main profiles, the ones worth listing.
|
||||
|
||||
* GitHub: [@flewkey](https://github.com/flewkey)
|
||||
* Twitter: [@flewkey](https://twitter.com/flewkey)
|
||||
* YouTube: [@flewkey](https://www.youtube.com/channel/UCRUfdaM8EiXu7SCfGl8FUpQ)
|
||||
* PeerTube: [@flewkey_channel@toobnix.org](https://toobnix.org/video-channels/flewkey_channel/)
|
||||
* Mastodon: [@flewkey@layer8.space](https://layer8.space/@flewkey)
|
||||
* Newgrounds: [@flewkey](https://flewkey.newgrounds.com/)
|
||||
* Soundcloud: [@flewkey](https://soundcloud.com/flewkey)
|
||||
* SDF GIT Society [@flewkey](https://git.sdf.org/flewkey)
|
||||
|
||||
---
|
||||
|
||||
## Contact
|
||||
|
||||
If you would like to contact me privately, please send me an e-mail if possible.
|
||||
Even a long, drawn out e-mail will take less time out of my day than the average
|
||||
text exchange. Thanks! <flewkey@2a03.party>
|
||||
|
||||
I can also be found at [##dystopia]({root}dystopia{ext}) on Freenode. While I
|
||||
encourage people to use the IRC channel, there is also a
|
||||
[Discord server]({root}dystopia{ext}) linked to the chatroom for those who find
|
||||
IRC inconvenient for some reason.
|
30
pages/dystopia.md
Normal file
30
pages/dystopia.md
Normal file
@ -0,0 +1,30 @@
|
||||
template: page
|
||||
title: Dystopia
|
||||
license: CC-BY
|
||||
|
||||
# Dystopia
|
||||
|
||||
Dystopia is a personal Discord server and IRC channel which I run for myself,
|
||||
and various other people I know. It is also one of the easiest places to contact
|
||||
me.
|
||||
|
||||
All messages on the IRC channel will be mirrored to Discord and logged.
|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
|
||||
* \#\#dystopia on Freenode
|
||||
([webchat](https://webchat.freenode.net/?channels=##dystopia))
|
||||
* <https://discord.gg/vQ8VEAU> on Discord
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
* Use common sense.
|
||||
* Do not annoy others.
|
||||
* Absolutely no flame wars.
|
||||
* Conduct yourself as a guest.
|
||||
* Never post slurs, I won't allow it.
|
||||
* Avoid posting personal information.
|
19
pages/index.md
Normal file
19
pages/index.md
Normal file
@ -0,0 +1,19 @@
|
||||
template: page
|
||||
title: Homepage
|
||||
license: CC-BY
|
||||
|
||||
# Homepage
|
||||
|
||||
Ahoy, my name is Ryan Fox. I am a Canadian guy who likes programming and music.
|
||||
|
||||
Have you come to [read about me]({root}about{ext})?
|
||||
|
||||
If not, feel free to [read some blog posts]({root}blog/) or
|
||||
[listen to my music]({root}music/).
|
||||
|
||||
---
|
||||
|
||||
## Projects
|
||||
|
||||
* [flewkey-overlay](https://git.sdf.org/flewkey/flewkey-overlay) - My personal Gentoo overlay.
|
||||
* [minecraft-tweaks-2a03](https://git.sdf.org/flewkey/minecraft-tweaks-2a03) - A basic Minecraft mod.
|
21
posts/2020-06-30-blog.md
Normal file
21
posts/2020-06-30-blog.md
Normal file
@ -0,0 +1,21 @@
|
||||
template: post
|
||||
title: Website update
|
||||
author: flewkey
|
||||
timestamp: 1593548958
|
||||
license: CC-BY
|
||||
|
||||
I like blogs. Blogs are one of the only suitable platforms for people to
|
||||
properly present ideas. There are no character limits, the author can embed
|
||||
whatever they want, and — most importantly — they can disable the
|
||||
comments section. This caught my attention, so I decided to start my own blog.
|
||||
Unfortunately, blogging on my plain HTML website was a pain. It needed an
|
||||
update.
|
||||
|
||||
Multiple people had recommended Jekyll to me, and I had seen many others use it
|
||||
for their websites. Making a simple blog with it seemed simple, but extending
|
||||
it to handle a custom page for my music was a pain. It didn't help that I am far
|
||||
too lazy to learn about Ruby.
|
||||
|
||||
The solution was ridiculously simple: a Makefile and some Python scripts. I had
|
||||
to fiddle with it for a couple of hours, but I am quite happy with the result.
|
||||
There should be less typos in the RSS feeds now!
|
97
posts/2020-07-12-nds-constraint.md
Normal file
97
posts/2020-07-12-nds-constraint.md
Normal file
@ -0,0 +1,97 @@
|
||||
template: post
|
||||
title: nds-constrain't
|
||||
author: flewkey
|
||||
timestamp: 1594525504
|
||||
license: CC-BY
|
||||
|
||||
Once upon a time, shutterbug2000 discovered nds-constrain't: a bug in Nintendo's
|
||||
NTR SSL library that allowed it's connections to be easily intercepted. This
|
||||
made it possible to connect to alternative online services without ROM patching.
|
||||
|
||||
The bug itself is simple: the NDS SSL library does not care whether or not a
|
||||
certificate is authorized to act as a certificate authority. This means that
|
||||
— with any valid certificate — we can sign whatever we want, even a
|
||||
certificate under a false hostname.
|
||||
|
||||
A guide to using this bug for fun and profit is now available on the
|
||||
[official page](https://github.com/KaeruTeam/nds-constraint), which is much
|
||||
better written than mine. However, you are free to keep reading this one.
|
||||
|
||||
---
|
||||
|
||||
### Getting the Wii client certificate
|
||||
|
||||
As explained in the [official page](https://github.com/KaeruTeam/nds-constraint)
|
||||
for nds-constrain't, the Wii client certificate is signed by Nintendo and
|
||||
considered valid. Therefore, we can use it's key to sign whatever we want. You
|
||||
_could_ grab it from a Wii, but it is much easier to download it from
|
||||
[Larsenv's page](https://larsenv.github.io/NintendoCerts/index.html). You will
|
||||
want to use the link labelled "Wii NWC Prod 1", by the way.
|
||||
|
||||
### Converting it to a useable format
|
||||
|
||||
The file is a PKCS12, and we can't do anything useful with it until we extract
|
||||
the certificate and the private key. Thankfully, this is pretty simple.
|
||||
|
||||
openssl pkcs12 -in WII_NWC_1_CERT.p12 -passin pass:alpine -passout pass:alpine -out keys.txt
|
||||
|
||||
That command will export the X.509 certificate and private key from the archive,
|
||||
and store the output in keys.txt. They can then be copied into their appropriate
|
||||
files, which I will name NWC.crt and NWC.key.
|
||||
|
||||
### Signing your certificate
|
||||
|
||||
Instructions for this are listed on the official GitHub page, but I have copied
|
||||
them for reference. If I remember correctly, the DS can only handle the SHA-1
|
||||
and MD5 hash formats, so pay attention to the `-sha1` flag.
|
||||
|
||||
openssl genrsa -out server.key 1024
|
||||
openssl req -new -key server.key -out server.csr
|
||||
openssl x509 -req -in server.csr -CA NWC.crt -CAkey NWC.key -CAcreateserial -out server.crt -days 3650 -sha1
|
||||
|
||||
Your webserver probably wants the certificate chain as well, so let's generate
|
||||
that as well.
|
||||
|
||||
cat server.crt NWC.crt > server-chain.crt
|
||||
|
||||
We are ready to rock and roll!
|
||||
|
||||
### Using your phony certificate
|
||||
|
||||
Once the SSL certificate is installed, you may run into issues connecting with
|
||||
your DS. This because your NDS only knows how to use SSLv3, with the SHA-1 or
|
||||
MD5 cipher sets. Enabling SSLv3 and SHA-1 isn't always possible with webservers,
|
||||
so I recommend using NGINX as a reverse-proxy. To enable DS compatibility for
|
||||
NGINX, add the following lines to your NGINX configuration.
|
||||
|
||||
ssl_protocols SSLv3;
|
||||
ssl_ciphers ECDHE-RSA-AES128-SHA;
|
||||
|
||||
Most services on Nintendo consoles make liberal use of headers. Because of this,
|
||||
some extra options need to be enabled.
|
||||
|
||||
underscores_in_headers on;
|
||||
proxy_pass_request_headers on;
|
||||
|
||||
Because we have enabled insecure SSL settings on NGINX, you probably don't want
|
||||
to use it for any mission-critical web applications. If you continue having
|
||||
issues with NDS connectivity, please contact me.
|
||||
|
||||
### Having fun
|
||||
|
||||
The possibilities are infinite. Want to run services through a debugging proxy?
|
||||
Implement WFC protocols? Make a Flipnote Studio server? All of this is possible
|
||||
without ROM patches!
|
||||
|
||||
---
|
||||
|
||||
### Update
|
||||
|
||||
After receiving some e-mails, I have learned that the NDS-supported ciphers have
|
||||
been disabled in OpenSSL versions past 1.0.2g, unless configured with
|
||||
"enable-weak-ssl-ciphers". This means that you may have to re-build NGINX (or
|
||||
mod_ssl for Apache) to get it working.
|
||||
|
||||
If you have the means, I suggest taking Wireshark captures to find the cause of
|
||||
any SSL issues. Enabling debug logging in NGINX can also help you pinpoint
|
||||
handshake errors. If all else fails, you can find my e-mail on the about page.
|
27
scripts/gen_blog.py
Executable file
27
scripts/gen_blog.py
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import markdown
|
||||
from template import template
|
||||
|
||||
def gen_list(files, ext):
|
||||
md = markdown.Markdown(extensions = ["meta", "extra"])
|
||||
items = ""
|
||||
for post in files:
|
||||
with open("posts/"+post, "r", encoding="utf-8") as file_in:
|
||||
html = md.convert(file_in.read())
|
||||
md.Meta["template"] = "post_preview"
|
||||
items += template(html, "blog/"+post[:-3]+ext, ext, md.Meta)
|
||||
return items
|
||||
|
||||
def main():
|
||||
meta = {"template": "post_list"}
|
||||
ext = "."+sys.argv[2].split(".")[-1]
|
||||
files = sorted(os.listdir(sys.argv[1]), reverse=True)
|
||||
output = template(gen_list(files, ext), sys.argv[2], ext, meta)
|
||||
with open(sys.argv[2], "w+", encoding="utf-8") as file_out:
|
||||
file_out.write(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
28
scripts/gen_music.py
Executable file
28
scripts/gen_music.py
Executable file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from template import template
|
||||
|
||||
def gen_list(music, ext):
|
||||
items = ""
|
||||
for track in music:
|
||||
track["template"] = "track_preview"
|
||||
track["file_size"] = str(os.path.getsize("music/"+track["id"]+".mp3"))
|
||||
if "group" in track:
|
||||
track["group_text"] = "<span>Part of "+track["group"]+"</span><br/>"
|
||||
items += template("", sys.argv[2], ext, track)
|
||||
return items
|
||||
|
||||
def main():
|
||||
meta = {"template": "music_list"}
|
||||
ext = "."+sys.argv[2].split(".")[-1]
|
||||
with open(sys.argv[1], "r", encoding="utf-8") as file_in:
|
||||
music = json.loads(file_in.read())
|
||||
output = template(gen_list(music, ext), sys.argv[2], ext, meta)
|
||||
with open(sys.argv[2], "w+", encoding="utf-8") as file_out:
|
||||
file_out.write(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
90
scripts/template.py
Normal file
90
scripts/template.py
Normal file
@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import markdown
|
||||
from datetime import datetime
|
||||
from email import utils
|
||||
|
||||
def get_path(path, ext_in, ext_out):
|
||||
path = path[len("pages"):]
|
||||
if path[-len("index"+ext_in):] == "index"+ext_in:
|
||||
return path[:-len("index"+ext_in)]
|
||||
return path[:-len(ext_in)] + ext_out
|
||||
|
||||
def get_dir(path):
|
||||
return "/".join(path.split("/")[1:-1])+"/"
|
||||
|
||||
def get_root(path):
|
||||
root = ""
|
||||
for i in range(len(path.split("/"))-2):
|
||||
root += "../"
|
||||
return root
|
||||
|
||||
licenses = {
|
||||
"CC-BY": ["cc-by", "CC BY 4.0", "https://creativecommons.org/licenses/by/4.0/"]
|
||||
}
|
||||
|
||||
def get_badge(license, root):
|
||||
if license not in licenses:
|
||||
return ""
|
||||
data = licenses[license]
|
||||
return "<a class=\"badge\" title=\""+data[1]+"\" href=\""+data[2]+"\"><img src=\""+root+"badges/"+data[0]+".png\" alt=\""+data[1]+"\"/></a>"
|
||||
|
||||
def read_template(template, meta_in):
|
||||
if template[:10] != "meta: yes\n":
|
||||
return [template, {"meta": "no"}]
|
||||
data = template[:-1].split("\n\n") # Strip trailing newline
|
||||
md = markdown.Markdown(extensions = ["meta"])
|
||||
md.convert(data[0])
|
||||
content = "\n\n".join(data[1:])
|
||||
content = content.replace("{", "{{").replace("}", "}}")
|
||||
meta = meta_in.copy()
|
||||
meta.update(md.Meta)
|
||||
return [content, MetaDict(meta)]
|
||||
|
||||
defaults = {
|
||||
"base": "https://flewkey.com/",
|
||||
"title": "Untitled",
|
||||
"author": "flewkey",
|
||||
"ext": ".html",
|
||||
"head": ""
|
||||
}
|
||||
|
||||
class MetaDict(dict):
|
||||
def __missing__(self, key):
|
||||
return defaults[key] if key in defaults else ""
|
||||
def __getitem__(self, key):
|
||||
value = dict.__getitem__(self, key)
|
||||
if isinstance(value, list):
|
||||
return "\n".join(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
def template(content, path, ext, meta):
|
||||
global base
|
||||
meta = MetaDict(meta)
|
||||
if meta["template"] == None:
|
||||
return content.format_map(meta)
|
||||
with open("templates/"+meta["template"]+ext, "r", encoding="utf-8") as file:
|
||||
t_content = file.read()
|
||||
t_info = read_template(t_content, meta)
|
||||
if t_info[1]["meta"] != "no" and "template" in t_info[1]:
|
||||
t_content = template(t_info[0], path, ext, t_info[1])
|
||||
if "root" not in meta:
|
||||
meta["root"] = get_root(path)
|
||||
if "home" not in meta:
|
||||
meta["home"] = "." if meta["root"] == "" else meta["root"]
|
||||
if "full_path" not in meta:
|
||||
meta["full_path"] = get_path(path, ext, meta["ext"])
|
||||
if "full_dir" not in meta:
|
||||
meta["full_dir"] = get_dir(path)
|
||||
if "badge" not in meta and ext == ".html":
|
||||
meta["badge"] = get_badge(meta["license"], meta["root"])
|
||||
if "date" not in meta and "timestamp" in meta:
|
||||
meta["date"] = datetime.fromtimestamp(int(meta["timestamp"])).isoformat().split("T")[0]
|
||||
if "pub_date" not in meta and "timestamp" in meta:
|
||||
meta["pub_date"] = utils.format_datetime(datetime.fromtimestamp(int(meta["timestamp"])))
|
||||
meta["head"] += "\n<link rel=\"canonical\" href=\""+meta["base"]+meta["full_path"]+"\"/>"
|
||||
meta["content"] = content.format_map(meta)
|
||||
if "description" not in meta and ext == ".html":
|
||||
meta["description"] = meta["content"].split("</p>")[0]+"</p>" # Disgusting!
|
||||
return t_content.format_map(meta)
|
16
scripts/template_md.py
Executable file
16
scripts/template_md.py
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import markdown
|
||||
from template import template
|
||||
|
||||
def main():
|
||||
md = markdown.Markdown(extensions = ["meta", "extra"])
|
||||
with open(sys.argv[1], "r", encoding="utf-8") as file_in:
|
||||
html = md.convert(file_in.read())
|
||||
output = template(html, sys.argv[2], ".html", md.Meta) if "template" in md.Meta else html
|
||||
with open(sys.argv[2], "w+", encoding="utf-8") as file_out:
|
||||
file_out.write(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
9
static/.htaccess
Normal file
9
static/.htaccess
Normal file
@ -0,0 +1,9 @@
|
||||
ErrorDocument 404 /404.html
|
||||
|
||||
Redirect 301 /nds-constraint.html /blog/2020-07-12-nds-constraint.html
|
||||
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} off [OR]
|
||||
RewriteCond %{HTTP_HOST} ^www\. [NC]
|
||||
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
|
||||
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
|
BIN
static/assets/avatar.png
Normal file
BIN
static/assets/avatar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
static/badges/cc-by.png
Normal file
BIN
static/badges/cc-by.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 430 B |
BIN
static/favicon.ico
Normal file
BIN
static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
14
static/music/player.js
Normal file
14
static/music/player.js
Normal file
@ -0,0 +1,14 @@
|
||||
function getAudio(player) {
|
||||
return player.getElementsByTagName("audio")[0];
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
var players = document.getElementsByClassName("player");
|
||||
for (var i = 0; i < players.length; i++) {
|
||||
getAudio(players[i])["queue"] = i;
|
||||
getAudio(players[i]).addEventListener('ended', function(event) {
|
||||
const next = event.target["queue"] + 1;
|
||||
if (next < players.length) getAudio(players[next]).play();
|
||||
});
|
||||
}
|
||||
}
|
52
static/pgp.txt
Normal file
52
static/pgp.txt
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
mCHt
|
||||
=BBAA
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
1
static/ssh.txt
Normal file
1
static/ssh.txt
Normal file
@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCnRLK2qyF44Fzcy6uyhZQwT1V0o8yTaybpXCMIYGXbOAAdWvdNYkg+smrebTgOq6BQsbiIl35x+lTjUI3vUnIRiaD7NQ6jKFW0sjhtxj5m48fT3lv2hNtd1G+zAokw9/K0//l/Ud93AijCgVP10UQi9Fi4a4Poim1B/DtUa5Bs0yp0PCSh8ZAimEhVpNby0GiI14iSnO09x/jHUC1o8hrq6zzZcsdo1Ar0Gf0NLBG9CnDG4W+wBryEzkkwpBEXT1j+cmY7Y/vs8x/UWULF+keIynb5WMCqzJAye1FdiMvx45hQiClKAJO7Qp3E1Nb/LzLiic8/s5zBSjatWSibnpF1yEuDUiBDKI8ImWJgIG5odenLgqqIw2VN5MQ6L/STseMvFN0zvqDGtGR9XCOvP0hOprP89eG0vtJLl7pUoZ3hDzdrp4tZDJczgkRTTWxkQ5yPkDaF6+B42l1FmwYJUFF9JiD+cEBC9/499yKqH++7DeynFZb5uzxAtwgu0duvrurrt2jzF0JQJ6zqzPV63lM/WrwlXPOE40rRBhShwmpLlFDB0cwchO0FPFmxfdL+mp3YXWVRnyg7QniitEtMmMmWZQVMN2/5TN9h/gziyux23BVaYsnYt+vFDmtXOztgbR/lVhgKZUIfR+CTr7qiHTkaDD8Ae7+KwruFJq3LjOkwsw== flewkey@2a03.party
|
266
static/style.css
Normal file
266
static/style.css
Normal file
@ -0,0 +1,266 @@
|
||||
body {
|
||||
font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||
font-size: 18px;
|
||||
line-height: 2;
|
||||
margin: 0 0 0 0;
|
||||
padding: 0 0 0 0;
|
||||
background-color: #F8F8F8;
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
header {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 840px;
|
||||
height: 128px;
|
||||
border-bottom: solid 2px #AAAAAA;
|
||||
padding: 32px 0 32px 0;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
header img {
|
||||
display: inline-block;
|
||||
height: 128px;
|
||||
width: 128px;
|
||||
border-radius: 32px;
|
||||
margin-right: 16px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
header div.info div {
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
margin-left: 16px;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
header div.info span.title {
|
||||
display: block;
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
header div.info span.subtext {
|
||||
display: block;
|
||||
font-size: 32px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
nav {
|
||||
text-align: center;
|
||||
height: 42px;
|
||||
line-height: 32px;
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
nav a {
|
||||
color: #666666;
|
||||
display: block;
|
||||
}
|
||||
|
||||
nav a:hover {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
main {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 840px;
|
||||
padding-left: 32px;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
footer {
|
||||
text-align: center;
|
||||
border-top: solid 2px #AAAAAA;
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
margin-top: 48px;
|
||||
font-size: 16px;
|
||||
background-color: #DDDDDD;
|
||||
}
|
||||
|
||||
footer span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
span, h1, h2, h3, h4 {
|
||||
padding: 0 0 0 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 18px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
line-height: 1;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
div.title-subtext {
|
||||
color: #555555;
|
||||
font-weight: normal;
|
||||
font-size: 20px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0074D9;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 0;
|
||||
border: 0;
|
||||
border-top: 2px solid #AAAAAA;
|
||||
margin-top: 48px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
div.block {
|
||||
padding-top: 48px;
|
||||
padding-bottom: 48px;
|
||||
border-top: solid 2px #AAAAAA;
|
||||
}
|
||||
div.block:first-of-type {
|
||||
padding-top: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 950px) {
|
||||
header {
|
||||
height: 172px;
|
||||
}
|
||||
|
||||
header div.info {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header div.info img {
|
||||
float: none;
|
||||
}
|
||||
|
||||
header div.info div {
|
||||
padding-top: 19px;
|
||||
padding-bottom: 19px;
|
||||
float: none;
|
||||
}
|
||||
|
||||
header div.info span.title {
|
||||
font-size: 50px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
header div.info span.subtext {
|
||||
font-size: 26px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
nav {
|
||||
float: none;
|
||||
line-height: 48px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
nav a {
|
||||
display: inline;
|
||||
margin-right: 32px;
|
||||
margin-left: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
body {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
header {
|
||||
height: 220px;
|
||||
min-width: 230px;
|
||||
padding: 16px 16px 16px 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
header img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
header div.info div {
|
||||
margin: 0 0 0 0;
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
header div.info span.title {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
header div.info span.subtext {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
nav a {
|
||||
display: inline;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
div.block {
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
div.title-subtext {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
21
templates/music_list.html
Normal file
21
templates/music_list.html
Normal file
@ -0,0 +1,21 @@
|
||||
meta: yes
|
||||
title: Music
|
||||
description: Listen to all of the music I've made!
|
||||
head: <script src="player.js"></script>
|
||||
<link rel="alternate" type="application/rss+xml" title="Ryan's Music" href="feed.xml"/>
|
||||
template: page
|
||||
|
||||
<style>
|
||||
audio {{
|
||||
width: 100%;
|
||||
}}
|
||||
div.player audio {{
|
||||
margin-top: 12px;
|
||||
}}
|
||||
</style>
|
||||
<h1>Music</h1>
|
||||
<p>On this page, you can find all of my attempts at music.<br/>If you would like to listen to it elsewhere, you can find my other profiles on my <a href="{root}about{ext}">about page</a>.</p>
|
||||
<p>Subscribe to my <a href="feed.xml">RSS feed</a> to see my posts first.</p>
|
||||
<hr/>
|
||||
<!--Using a <ul> would be more structural, but that's too much voodoo.-->
|
||||
{content}
|
5
templates/music_list.xml
Normal file
5
templates/music_list.xml
Normal file
@ -0,0 +1,5 @@
|
||||
meta: yes
|
||||
title: Music
|
||||
template: rss
|
||||
|
||||
{content}
|
34
templates/page.html
Normal file
34
templates/page.html
Normal file
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="{root}style.css"/>
|
||||
<link rel="icon" type="image/x-icon" href="{root}favicon.ico"/>
|
||||
<title>{title} - flewkey</title>
|
||||
{head}
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="info">
|
||||
<img src="{root}assets/avatar.png" alt="My avatar"/>
|
||||
<div>
|
||||
<span class="title">flewkey</span>
|
||||
<span class="subtext">Level 10 Computer Mage</span>
|
||||
</div>
|
||||
</div>
|
||||
<nav>
|
||||
<a href="{home}">Home</a>
|
||||
<a href="{root}about{ext}">About</a>
|
||||
<a href="{root}blog/">Blog</a>
|
||||
<a href="{root}music/">Music</a>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
{content}
|
||||
</main>
|
||||
<footer>
|
||||
<span>Copyright © 2020 flewkey</span>
|
||||
{badge}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
8
templates/post.html
Normal file
8
templates/post.html
Normal file
@ -0,0 +1,8 @@
|
||||
meta: yes
|
||||
head: <meta name="description" content="{description}"/>
|
||||
<meta name="author" content="{author}"/>
|
||||
template: page
|
||||
|
||||
<h1>{title}
|
||||
<div class="title-subtext"><span>Published on {date} by {author}</span></div></h1>
|
||||
{content}
|
11
templates/post_list.html
Normal file
11
templates/post_list.html
Normal file
@ -0,0 +1,11 @@
|
||||
meta: yes
|
||||
title: Blog
|
||||
description: View a post, then view more posts.
|
||||
head: <link rel="alternate" type="application/rss+xml" title="Ryan's Blog" href="feed.xml"/>
|
||||
template: page
|
||||
|
||||
<h1>Blog</h1>
|
||||
<p>The chances of seeing a new blog post are the same as winning the lottery while getting struck by lightning twice on a leap day. If you still come across a post, I promise to make it disappointing.</p>
|
||||
<p>Subscribe to my <a href="feed.xml">RSS feed</a> to see my posts first.</p>
|
||||
<hr/>
|
||||
{content}
|
5
templates/post_list.xml
Normal file
5
templates/post_list.xml
Normal file
@ -0,0 +1,5 @@
|
||||
meta: yes
|
||||
title: Blog
|
||||
template: rss
|
||||
|
||||
{content}
|
5
templates/post_preview.html
Normal file
5
templates/post_preview.html
Normal file
@ -0,0 +1,5 @@
|
||||
<div class="block">
|
||||
<a href="{full_path}"><h3>{title}</h3></a>
|
||||
<p>{description}</p>
|
||||
<a href="{full_path}">Read more</a>
|
||||
</div>
|
9
templates/post_preview.xml
Normal file
9
templates/post_preview.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<item>
|
||||
<title>{title}</title>
|
||||
<link>{{base}}{{full_dir}}{full_path}</link>
|
||||
<guid isPermaLink="true">{{base}}{{full_dir}}{full_path}</guid>
|
||||
<pubDate>{pub_date}</pubDate>
|
||||
<description>{description}</description>
|
||||
<content:encoded><![CDATA[{content}]]></content:encoded>
|
||||
<author>{author}</author>
|
||||
</item>
|
12
templates/rss.xml
Normal file
12
templates/rss.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
|
||||
<channel>
|
||||
<title>Ryan's {title}</title>
|
||||
<link>{base}{full_dir}</link>
|
||||
<atom:link href="{base}{full_path}" rel="self" type="application/rss+xml"/>
|
||||
<description>{description}</description>
|
||||
<language>en-ca</language>
|
||||
<managingEditor>{author}</managingEditor>
|
||||
{content}
|
||||
</channel>
|
||||
</rss>
|
6
templates/track_preview.html
Normal file
6
templates/track_preview.html
Normal file
@ -0,0 +1,6 @@
|
||||
<div id="audio_{id}" class="block player">
|
||||
<h4>{name}</h4>
|
||||
{group_text}
|
||||
<span>Published on {date}</span>
|
||||
<audio controls><source src="{id}.mp3" type="audio/mpeg"/></audio>
|
||||
</div>
|
9
templates/track_preview.xml
Normal file
9
templates/track_preview.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<item>
|
||||
<title>{name}</title>
|
||||
<link>{{base}}{{full_dir}}#audio_{id}</link>
|
||||
<guid isPermaLink="true">{{base}}{{full_dir}}#audio_{id}</guid>
|
||||
<enclosure length="{file_size}" url="{{base}}{{full_dir}}{id}.mp3" type="audio/mpeg"/>
|
||||
<pubDate>{pub_date}</pubDate>
|
||||
<description>{description}</description>
|
||||
<author>{{author}}</author>
|
||||
</item>
|
Loading…
x
Reference in New Issue
Block a user