This commit is contained in:
dreamer 2025-10-12 21:35:48 +02:00
commit 0e949bb56f
19 changed files with 740 additions and 0 deletions

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
# FROM mileschou/lapis:alpine as wasted.audio
FROM openresty/openresty:1.27.1.2-4-alpine-fat
ENV LAPIS_VERSION=1.16.0
RUN apk add openssl-dev git
RUN opm get spacewander/luafilesystem
RUN luarocks install luasec
RUN luarocks install busted
RUN luarocks install --check-lua-versions markov-text
RUN luarocks install lapis ${LAPIS_VERSION}
RUN luarocks install moonscript
WORKDIR /srv/lapis
CMD lapis server $ENVIRONMENT

32
code/app.lua Normal file
View File

@ -0,0 +1,32 @@
local lapis = require("lapis")
local config = require("lapis.config").get()
local json_params = require("lapis.application").json_params
local app = lapis.Application()
app:enable("etlua")
app.layout = require "views.layout"
local autoload = require("lapis.util").autoload
local handlers = autoload("handlers")
local page_titles = {
name = "DRMR",
url = "drmr.nl"
}
app:get("/", function(self)
self.titles = page_titles
return handlers.Roothandler(self)
end)
app:get("videos", "/videos", function(self)
self.titles = page_titles
return handlers.Videohandler(self)
end)
app:get("links", "/links", function(self)
self.titles = page_titles
return handlers.Linkhandler(self)
end)
return app

22
code/config.lua Normal file
View File

@ -0,0 +1,22 @@
local config = require("lapis.config")
config({"development", "production"}, {
host = "drmr.nl",
greeting = "Totally Wasted",
mount = "/mnt/data/",
postgres = {
host = "postgres",
user = "postgres",
password = "the_password",
database = "postgres"
}
})
config("production", {
greeting = "nothing here yet",
postgres = {
password = os.getenv('POSTGRES_PASSWORD')
},
logging = {
queries = false
}
})

55
code/drmr/utils.lua Normal file
View File

@ -0,0 +1,55 @@
local lfs = require("lfs_ffi")
local cjson = require("cjson")
local utils = {}
-- we want to list the contents of a dir
function utils:dirlist( path )
local files, dirs, images, audio = {}, {}, {}, {}
for file in lfs.dir( path ) do
local filepath = path .. "/" .. file
local attribute = lfs.attributes( filepath, "mode" ) or "nil"
if file ~= "." and file ~= ".." and not string.match(file, ".filepart") then
if lfs.attributes( filepath, "mode" ) == "file" then
if utils:match_image( file ) then
table.insert( images, file )
elseif utils:match_audio( file) then
table.insert( audio, file )
else
table.insert( files, file )
end
elseif lfs.attributes( filepath, "mode" ) == "directory" then
table.insert( dirs, file )
end
end
end
table.sort( images )
table.sort( files )
table.sort( dirs )
table.sort( audio )
local stuff = {
files = files,
dirs = dirs,
images = images,
audio = audio
}
return stuff
end
-- open a json file and return the table
function utils:opendata( path )
local data = io.open(path)
if data then
local data_file = data:read("a")
data:close()
local data_decode = cjson.decode(data_file)
return data_decode
else
return nil
end
end
return utils

View File

@ -0,0 +1,14 @@
local autoload = require("lapis.util").autoload
local config = require("lapis.config").get()
local utils = require("drmr.utils")
local drmr = autoload("drmr")
local function Linkhandler(self)
self.promo = utils:opendata(config.mount .. "promo.json")
return { render = "links"}
end
return Linkhandler

View File

@ -0,0 +1,24 @@
local autoload = require("lapis.util").autoload
local config = require("lapis.config").get()
local utils = require("drmr.utils")
local drmr = autoload("drmr")
local function Roothandler(self)
local function compare( a, b )
if a.stop == "current" or b.stop == "current" then
return b.start < a.start
end
return a.stop > b.stop
end
-- table.sort(unsort_career.career, compare)
self.promo = utils:opendata(config.mount .. "promo.json")
return { render = "root"}
end
return Roothandler

View File

@ -0,0 +1,15 @@
local autoload = require("lapis.util").autoload
local config = require("lapis.config").get()
local utils = require("drmr.utils")
local drmr = autoload("drmr")
local function Videohandler(self)
self.videos = utils:opendata(config.mount .. "videos.json")
return { render = "video"}
end
return Videohandler

83
code/mime.types Normal file
View File

@ -0,0 +1,83 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/x-lua lua;
application/x-moonscript moon;
application/x-javascript js;
application/atom+xml atom;
application/rss+xml rss;
application/json json;
application/x-bittorrent torrent;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
image/svg+xml svg svgz;
image/webp webp;
application/java-archive jar war ear;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream eot;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

50
code/nginx.conf Normal file
View File

@ -0,0 +1,50 @@
worker_processes ${{NUM_WORKERS}};
error_log stderr notice;
daemon off;
pid logs/nginx.pid;
env POSTGRES_PASSWORD;
env STATION_SECRET_1;
env STATION_SECRET_2;
env STATION_SECRET_3;
events {
worker_connections 1024;
}
http {
include mime.types;
resolver 127.0.0.11;
init_by_lua_block {
require("socket")
require("lpeg")
math.randomseed(os.time()+ngx.worker.id())
}
server {
listen ${{PORT}};
lua_code_cache ${{CODE_CACHE}};
add_header Access-Control-Allow-Origin *;
location /data/ {
root /mnt;
}
location /static/ {
alias static/;
}
location / {
default_type text/html;
content_by_lua_block {
require("lapis").serve("app")
}
}
location /favicon.ico {
alias static/favicon.ico;
}
}
}

BIN
code/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

308
code/static/style.css Normal file
View File

@ -0,0 +1,308 @@
* {
box-sizing: border-box;
}
:root {
--main-bg-color: #222222;
--base-bg-color: #111111;
--text-color: #9d9d9d;
--wstd-green: #28a07d;
--wstd-yellow: #d5af14;
--wstd-blue: #186da1;
--wstd-red: #FF473D;
--wstd-purple: #662042;
}
body {
width: 95%;
padding-left: 0%;
padding-right: 0%;
background-color: var(--main-bg-color);
font-family: monospace;
display: flex;
flex-direction: column;
}
.footer {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 5px 12px;
}
.p
{
color: #7e7e7e;
margin-bottom: 45px;
font-size: 10px;
}
.nav_bar {
width: 90%;
font-size: 12px;
margin: auto;
text-align: center;
color: var(--text-color);
font-weight: 600;
}
.nav_drmr {
text-decoration: none;
background: var(--base-bg-color);
display: inline-flex;
margin: 4px;
padding: 5px 12px;
}
.nav_drmr:hover {
animation: pulse 1.5s infinite;
}
.ascii
{
vertical-align: center;
background: var(--base-bg-color);
display: inline-flex;
flex-wrap: wrap;
justify-content: space-evenly;
margin: 4px;
padding: 5px 12px;
border-radius: 20px;
color: var(--text-color);
line-height: 1.1em;
white-space: pre;
text-align:left;
user-select: none;
}
/* == root page == */
.root
{
width: 90%;
margin-top: 20px;
margin-bottom: 40px;
display: flex;
justify-content: space-evenly;
}
.rootcontainer
{
width: 100%;
float: left;
clear: both;
justify-content: space-evenly;
flex-wrap: wrap;
}
.roottext
{
text-align: center;
color: var(--text-color);
font-weight: 600;
font-size: 10px;
text-decoration: none;
background: var(--base-bg-color);
/* display: inline-flex; */
/* margin: 4px; */
padding: 5px 12px;
border-radius: 20px;
/* column-count: 2; */
margin: auto;
margin-top: 20px;
margin-bottom: 40px;
float: center;
clear: both;
display: flex;
width: 250px;
justify-content: space-evenly;
}
.rootdesc
{
text-align: center;
color: var(--text-color);
font-weight: 600;
font-size: 13px;
text-decoration: none;
background: var(--base-bg-color);
padding: 5px 12px;
border-radius: 20px;
margin: auto;
margin-top: 20px;
margin-bottom: 40px;
float: center;
clear: both;
display: flex;
width: 300px;
justify-content: space-evenly;
white-space: pre-line;
user-select: none;
}
.videos
{
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
.releasevideo
{
height: 220px;
width: 350px;
color: var(--text-color);
font-weight: 600;
font-size: 10px;
text-decoration: none;
background: var(--base-bg-color);
display: inline-flex;
margin: 4px;
padding: 15px 12px;
border-radius: 20px;
}
.releaseembed
{
max-height:185px;
max-width:330px;
width: auto;
height: auto;
margin: 5px;
border-radius: 15px;
object-fit: cover;
overflow: hidden;
}
.ytembed
{
height: 185px;
width: 330px;
}
.link, .link:visited
{
color: inherit;
text-decoration: none;
}
.rootdesc:hover {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
-webkit-box-shadow: 0 0 0 0 rgba(40, 160, 125, 1);
}
70% {
-webkit-box-shadow: 0 0 0 10px rgba(255, 0, 0, 0);
}
100% {
-webkit-box-shadow: 0 0 0 0 rgba(255, 0, 0, 0);
}
}
@media screen and (min-width: 600px) {
body {
padding-left: 5%;
padding-right: 5%;
}
.ascii {
font-size: 14px;
}
.roottext {
font-size: 12px;
width: 300px;
}
.rootdesc {
font-size: 15px;
width: 450px;
}
.nav_bar {
font-size: 16px;
}
.releasevideo
{
height: 280px;
min-width:460px;
font-size: 12px;
margin: 5px;
}
.releaseembed
{
max-height:247px;
max-width:440px;
width: auto;
height: auto;
margin: 5px;
border-radius: 15px;
object-fit: cover;
overflow: hidden;
}
.ytembed
{
height: 247px;
width: 440px;
}
}
@media screen and (min-width: 768px) {
body {
padding-left: 10%;
padding-right: 10%;
}
.ascii {
font-size: 17px;
}
.roottext {
font-size: 15px;
width: 350px;
}
.rootdesc {
font-size: 18px;
width: 550px;
}
.nav_bar {
font-size: 20px;
}
.releasevideo
{
height: 350px;
min-width: 580px;
margin: 6px;
font-size: 14px;
}
.releaseembed
{
max-height:315px;
max-width:560px;
width: auto;
height: auto;
margin: 5px;
border-radius: 15px;
object-fit: cover;
overflow: hidden;
}
.ytembed
{
height: 315px;
width: 560px;
}
}

5
code/views/about.etlua Normal file
View File

@ -0,0 +1,5 @@
<div class="rootdesc">
<% for i, item in ipairs(promo.description) do %>
<%= item %> <br>
<% end %>
</div>

25
code/views/layout.etlua Normal file
View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title><%= titles['name'] %>
<% if title then %>
- <%= title %>
<% end %>
</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/style.css">
</head>
<body class="body">
<div class="root">
<div class="rootcontainer">
<% render("views.navigation") %>
<% content_for("inner") %>
<div class="rootdesc">bookings &lt;at&gt; puikheid.nl</div>
</div>
</div>
</body>
</html>

7
code/views/links.etlua Normal file
View File

@ -0,0 +1,7 @@
<% for i, item in ipairs(promo.links) do %>
<a class="link" href="<%= item.url %>">
<div class="rootdesc">
<%= item.name %><br>
</div>
</a>
<% end %>

View File

@ -0,0 +1,17 @@
<li style="text-align: center;"><span class="ascii">
________ __________ _____ __________
\______ \\______ \ / \\______ \
| | \| _/ / \ / \| _/
| ` \ | \/ Y \ | \
/_______ /____|_ /\____|__ /____|_ /
\/ \/ \/ \/
</span></li>
<br>
<div class="nav_bar">
<a class="nav_drmr" href="/"><span style="color:#ffffff !important;">About</span></a>
<a class="nav_drmr" href="<%= url_for("videos") %>"><span style="color:#ffffff !important;">Live</span></a>
<a class="nav_drmr" href="<%= url_for("links") %>"><span style="color:#ffffff !important;">Online</span></a>
</div>
<br>

5
code/views/root.etlua Normal file
View File

@ -0,0 +1,5 @@
<div class="rootdesc">
<% for i, item in ipairs(promo.description) do %>
<%= item %> <br>
<% end %>
</div>

20
code/views/video.etlua Normal file
View File

@ -0,0 +1,20 @@
<div class="videos">
<% for i, item in ipairs(videos.videos) do %>
<div class="releasevideo">
<div class="releaseembed">
<iframe class="ytembed"
src="https://www.youtube.com/embed/<%= item %>"
title="YouTube video player"
frameborder="0"
showinfo=0
autohide=1
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen>
</iframe>
</div>
</div>
<% end %>
</div>

26
docker-compose-local.yaml Normal file
View File

@ -0,0 +1,26 @@
services:
drmr.nl:
environment:
- ENVIRONMENT
build: .
networks:
- web
volumes:
- ./code:/srv/lapis
- /media/drmr.nl:/mnt/data
labels:
- traefik.enable=true
- traefik.http.routers.wasted.rule=Host(`drmr.nl`)
- traefik.http.routers.wasted.entrypoints=web
- traefik.http.routers.wasted.middlewares=redirect-https-wasted
- traefik.http.middlewares.redirect-https-wasted.redirectscheme.scheme=https
- traefik.http.routers.wasted_ssl.rule=Host(`drmr.nl`)
- traefik.http.routers.wasted_ssl.entrypoints=websecure
- traefik.http.routers.wasted_ssl.tls.certresolver=myresolver
- traefik.http.services.wasted.loadbalancer.server.port=8080
networks:
web:
external: true

16
docker-compose.yaml Normal file
View File

@ -0,0 +1,16 @@
services:
drmr.nl:
environment:
- ENVIRONMENT
build: .
networks:
- web
volumes:
- ./code:/srv/lapis
- ./_assets:/mnt/data
ports:
- "8083:8080"
networks:
web:
external: true