Add basic files and nginx config

main
lambda 2 years ago
parent eca9020a76
commit 927ce65fc3
No known key found for this signature in database
GPG Key ID: 662ADE783CBB4026

@ -0,0 +1,8 @@
# syntax=docker/dockerfile:1
FROM nginx:1.22.0-alpine
WORKDIR /var/www/
COPY nginx/nginx.conf /etc/nginx/nginx.conf
RUN mkdir -p /var/www/website
COPY src /var/www/website
EXPOSE 80

@ -0,0 +1,12 @@
login:
docker login gitea.bjornmossa.net
start:
npx live-server ./src
build:
docker build . -t gitea.bjornmossa.net/radioiceberg/website
push: login
docker push gitea.bjornmossa.net/radioiceberg/website

@ -0,0 +1,50 @@
include /etc/nginx/modules_enabled/*.conf;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name radioiceberg.net www.radioiceberg.net localhost 127.0.0.1;
rewrite ^/(.*) https://radioiceberg.net/$1 permanent;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
include /etc/nginx/mime.types;
server_name radioiceberg.net www.radioiceberg.net localhost 127.0.0.1;
#SSL
#ssl_certificate /etc/letsencrypt/live/radioiceberg.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/radioiceberg.net/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/radioiceberg.net/chain.pem;
location / {
root /var/www/website;
index index.html;
}
location /stream {
proxy_read_timeout 3000;
proxy_connect_timeout 3000;
proxy_redirect off;
proxy_pass http://icecast:8000/iceberg.ogg;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /meta {
proxy_pass http://metadata:7000;
proxy_http_version 1.1;
proxy_connect_timeout 1d;
proxy_send_timeout 1d;
proxy_read_timeout 1d;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -0,0 +1,19 @@
{
"name": "Radio Iceberg",
"short_name": "Iceberg",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ded8d8",
"background_color": "#252525",
"display": "standalone"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Radio . Iceberg</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
property="og:image"
content="http://radioiceberg.net/images/social-preview.jpg"
/>
<meta
property="og:title"
content="Звуки севера, пронзающие пустоту космоса."
/>
<meta
property="og:description"
content="Наверху нихуя, внизу дохуя. Независимое интернет-радио."
/>
<meta property="og:type" content="music.radio_station" />
<meta
name="description"
content="Наверху нихуя, внизу дохуя. Независимое интернет-радио."
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="icons/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="icons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="icons/favicon-16x16.png"
/>
<link rel="manifest" href="icons/site.webmanifest" />
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>
<h1>Radio . Iceberg</h1>
<button class="play-stream">
<svg viewBox="0 0 2000 500">
<defs></defs>
<polygon
points="0,0, 2000,250, 2000,250, 0,500"
fill="var(--color-primary-1)"
>
<animate
id="play-button-animation"
attributeName="points"
dur="1.25s"
fill="freeze"
from="0,0, 2000,250, 2000,250, 0,500"
to="0,0, 2000,250, 2000,250, 0,500"
restart="always"
/>
</polygon>
</svg>
<audio controls preload="none" src="/stream" />
</button>
<div class="now-playing">
<div class="now-playing_title">now playing:</div>
<div class="now-playing_artist">We don't know'</div>
<div class="now-playing_song">yet...</div>
</div>
<div class="icebergs">
<svg viewBox="0 0 100 100">
<polygon
id="iceberg1"
points="0,0, 100,0, 100,100, 0,100"
fill="var(--color-primary-1)"
></polygon>
<polygon
id="iceberg2"
points="5,5, 95,5, 95,95, 5,95"
fill="var(--color-primary-2)"
></polygon>
<polygon
id="iceberg3"
points="10,10, 90,10, 90,90, 10,90"
fill="var(--color-complement-1)"
></polygon>
</svg>
</div>
<script src="main.js"></script>
</body>
</html>

@ -0,0 +1,115 @@
const STOP_STATE_POINTS = "650,0, 1350,0, 1350,500, 650,500";
const PLAY_STATE_POINTS = "0,0, 2000,250, 2000,250, 0,500";
const getAudio = () => document.querySelector("audio");
const getPlayButton = () => document.querySelector(".play-stream");
const getPlayButtonAnimation = () =>
document.getElementById("play-button-animation");
const hideAudio = () => {
const a = getAudio();
a.hidden = true;
};
const playAudio = () => {
getAudio()?.play();
};
const pauseAudio = () => {
getAudio()?.pause();
};
const setButtonPlayState = () => {
const animationNode = getPlayButtonAnimation();
animationNode.setAttribute("from", PLAY_STATE_POINTS);
animationNode.setAttribute("to", STOP_STATE_POINTS);
animationNode.beginElement();
};
const setButtonStopState = () => {
const animationNode = getPlayButtonAnimation();
animationNode.setAttribute("from", STOP_STATE_POINTS);
animationNode.setAttribute("to", PLAY_STATE_POINTS);
animationNode.beginElement();
};
const startIcebergsAnimation = () => {
[1, 2, 3].map((i) => {
const polygon = document.getElementById(`iceberg${i}`);
polygon.classList.add("active");
});
};
const stopIcebergsAnimation = () => {
[1, 2, 3].map((i) => {
const polygon = document.getElementById(`iceberg${i}`);
polygon.classList.remove("active");
});
};
const handleAudioPlay = () => {
playAudio();
setButtonPlayState();
startIcebergsAnimation();
};
const handleAudioStop = () => {
pauseAudio();
setButtonStopState();
stopIcebergsAnimation();
};
const addPlayerInteractions = () => {
const playerButton = getPlayButton();
const audio = getAudio();
playerButton.addEventListener("click", () => {
audio.paused ? handleAudioPlay() : handleAudioStop();
});
audio.addEventListener("timeupdate", () => {
window.requestAnimationFrame(() => {
document.documentElement.style.setProperty(
"--time",
`${audio.currentTime * 100}deg`
);
});
});
};
async function connectToServer() {
const ws = new WebSocket(`ws://${location.host}/meta`);
ws.addEventListener("message", changeMetadata);
}
const changeMetadata = (metadataEvent) => {
const metaObject = JSON.parse(metadataEvent.data);
const { artist, title } = metaObject;
const artistBlock = document.querySelector(".now-playing_artist");
const titleBlock = document.querySelector(".now-playing_song");
if (artist) {
artistBlock.innerHTML = artist;
} else {
artistBlock.innerHTML = "";
}
if (title) {
titleBlock.innerHTML = title;
document.title = `${title} on Radioiceberg`;
} else {
titleBlock.innerHTML = "";
}
if (artist && title) {
document.title = `${artist} - ${title} on Radioiceberg`;
}
};
const main = () => {
hideAudio();
addPlayerInteractions();
connectToServer();
};
document.addEventListener("DOMContentLoaded", main);

@ -0,0 +1,10 @@
const getAudio = () => document.querySelector("audio");
const getPlayButton = () => document.querySelector(".play-stream");
const getPlayButtonAnimation = () =>
document.getElementById("play-button-animation");
export {
getAudio,
getPlayButton,
getPlayButtonAnimation
};

@ -0,0 +1,14 @@
import { getAudio } from "./dom.js";
const hideAudio = () => {
const a = getAudio();
a.hidden = true;
};
const playAudio = () => {
getAudio()?.play();
};
const pauseAudio = () => {
getAudio()?.pause();
};

@ -0,0 +1,70 @@
@import url("styles/global.css");
@import url("styles/system.css");
body {
background-color: var(--color-primary-0);
color: var(--color-primary-1);
height: 100vh;
max-height: 100vh;
overflow: hidden;
position: relative;
line-height: 1.75;
padding: 1rem;
}
h1,
h2,
h3,
h4,
h5 {
margin: 3rem 0 1.38rem;
font-family: "Lato", sans-serif;
font-weight: 400;
line-height: 1.3;
}
h1 {
text-transform: uppercase;
}
h1 {
margin-top: 0;
font-size: 5.063rem;
}
.play-stream {
background: transparent;
border: none;
padding: 0;
width: 300px;
cursor: pointer;
}
.now-playing {
font-family: "Lato Light Italic";
font-size: 1.5rem;
}
.icebergs {
position: fixed;
bottom: 0;
width: 100%;
rotate: -45deg;
translate: 10% 50%;
max-height: 70vh;
}
#iceberg1,
#iceberg2,
#iceberg3 {
transition: transform 2s ease-in-out;
transform: translate(0);
}
#iceberg1.active {
transform: translate(0, calc(100px * sin(var(--time))));
}
#iceberg2.active {
transform: translate(0, calc(50px * cos(var(--time))));
}

@ -0,0 +1,9 @@
html {
font-size: 100%;
}
html,
body {
margin: 0;
padding: 0;
}

@ -0,0 +1,36 @@
/* Typography */
@font-face {
font-family: "Lato";
src: url("fonts/lato-regular-webfont.woff2") format("woff2"),
url("fonts/lato-regular-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "Lato Light Italic";
src: url("fonts/lato-lightitalic.woff2") format("woff2"),
url("fonts/lato-lightitalic.woff") format("woff");
font-weight: normal;
font-style: normal;
}
/* Colors */
:root {
--color-primary-0: #252525;
--color-primary-1: #ded8d8;
--color-primary-2: #7d7d7d;
--color-primary-3: #010101;
--color-primary-4: #0e0404;
--color-complement-0: #1e1e1e;
--color-complement-1: #adb2ad;
--color-complement-2: #646464;
--color-complement-3: #010101;
--color-complement-4: #030b03;
--time: 0;
--lol: calc(100px * sin(var(--time)));
}