Radio and Files services are deleted.
This commit is contained in:
parent
909c096c21
commit
08e6a17aa1
@ -1,3 +0,0 @@
|
||||
exports.host = "0.0.0.0";
|
||||
exports.port = 32202;
|
||||
exports.share_path = "/srv/ftp";
|
117
files/index.js
117
files/index.js
@ -1,117 +0,0 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { ENOENT, ECONNRESET } = require("constants");
|
||||
|
||||
const Koa = require("koa");
|
||||
const koaPug = require("koa-pug");
|
||||
const koaRouter = require("koa-router");
|
||||
|
||||
const config = require("./config");
|
||||
const util = require("../shared/util");
|
||||
|
||||
|
||||
|
||||
const SIZE_UNITS = [ "B", "KiB", "MiB", "GiB" ];
|
||||
|
||||
function addFileSizeUnit(size) {
|
||||
let i = 0;
|
||||
for (; size > 1024; size /= 1024) ++i;
|
||||
return [i > 0 ? size.toFixed(2) : size, SIZE_UNITS[i]];
|
||||
}
|
||||
|
||||
|
||||
function buildCurrentPathLink(path) {
|
||||
let currentPath = `<a href="/">root</a>`;
|
||||
|
||||
if (path.endsWith("/"))
|
||||
path = path.slice(1, path.length-1);
|
||||
|
||||
const path_parts = path.split("/");
|
||||
|
||||
for (let i = 0; i < path_parts.length; ++i) {
|
||||
let lnk = "";
|
||||
|
||||
for (let j = 0; j < i+1; ++j)
|
||||
lnk += `/${path_parts[j]}`;
|
||||
|
||||
currentPath += `/<a href="${encodeURI(lnk)}/">${path_parts[i]}</a>`;
|
||||
}
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
function sortFuncByNameField(a, b) {
|
||||
return (a.name > b.name) ? 1 : (a.name < b.name) ? -1 : 0;
|
||||
}
|
||||
|
||||
async function getDirectoryList(dir_path, orig_url) {
|
||||
let directories = [];
|
||||
let files = [];
|
||||
let total_files_size = 0;
|
||||
let directory = await fs.promises.opendir(dir_path);
|
||||
|
||||
for await (const dirent of directory) {
|
||||
const stat = await fs.promises.stat(path.join(dir_path, dirent.name));
|
||||
const [s, u] = addFileSizeUnit(stat.size);
|
||||
|
||||
if (stat.isDirectory())
|
||||
directories.push({
|
||||
name: dirent.name,
|
||||
link: `${encodeURIComponent(dirent.name)}/`,
|
||||
datetime: stat.mtime,
|
||||
size: "DIR" });
|
||||
else {
|
||||
total_files_size += stat.size;
|
||||
files.push({
|
||||
name: dirent.name,
|
||||
link: `/files${orig_url}${encodeURIComponent(dirent.name)}`,
|
||||
datetime: stat.mtime,
|
||||
size: `${s} ${u}` });
|
||||
}
|
||||
}
|
||||
|
||||
directories.sort(sortFuncByNameField);
|
||||
files.sort(sortFuncByNameField);
|
||||
|
||||
return [directories.concat(files), directories.length, files.length,
|
||||
addFileSizeUnit(total_files_size).join(' ')];
|
||||
}
|
||||
|
||||
function setRoutes() {
|
||||
return koaRouter().get('/(.*)?', async ctx => {
|
||||
const file_path = path.join(config.share_path, decodeURI(ctx.originalUrl));
|
||||
|
||||
let stat = await fs.promises.stat(file_path);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
const [items, total_directories, total_files, total_files_size]
|
||||
= await getDirectoryList(file_path, decodeURI(ctx.originalUrl));
|
||||
|
||||
await ctx.render('index', {
|
||||
clientTZ: util.getClientTimezone(ctx),
|
||||
main_site: util.getServiceByHost(ctx.header.host),
|
||||
current_path: buildCurrentPathLink(decodeURI(ctx.originalUrl)),
|
||||
total_files: total_files,
|
||||
total_files_size: total_files_size,
|
||||
total_directories: total_directories,
|
||||
items: items });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const app = new Koa();
|
||||
const pug = new koaPug({
|
||||
viewPath: path.join(__dirname, "views"),
|
||||
locals: {
|
||||
moment: (date, tz) => util.datetime(date, util.date_formats.file_date, tz), },
|
||||
app: app
|
||||
});
|
||||
|
||||
app.proxy = true;
|
||||
app
|
||||
.use(setRoutes().routes())
|
||||
// .on("error", err => { if (!err.code == ECONNRESET || !err.code == ENOENT) console.log(err.code); })
|
||||
.listen(config.port, config.host);
|
||||
|
||||
console.log("Arav's dwelling / Files is up.");
|
@ -1,170 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'Roboto Condensed';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('RobotoCondensed'), local('RobotoCondensed-Regular'),
|
||||
url(/shared/fonts/RobotoCondensed-Regular.ttf); }
|
||||
|
||||
:root {
|
||||
--background-color: #0a0a0a;
|
||||
--primary-color: #cd2682;
|
||||
--secondary-color: #9f2b68;
|
||||
--text-color: #f5f5f5;
|
||||
--text-indent: 1.6rem;
|
||||
--overlay-background-color: #f5f5f574;
|
||||
scrollbar-color: var(--primary-color) var(--background-color); }
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--background-color: #f5f5f5;
|
||||
--primary-color: #9f2b68;
|
||||
--secondary-color: #cd2682;
|
||||
--text-color: #0a0a0a;
|
||||
--overlay-background-color: #0a0a0a74; } }
|
||||
|
||||
* { margin: 0; }
|
||||
|
||||
::selection {
|
||||
background-color: var(--secondary-color);
|
||||
color: var(--background-color); }
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none; }
|
||||
|
||||
a:hover {
|
||||
color: var(--secondary-color);
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
transition: .5s; }
|
||||
|
||||
p {
|
||||
text-align: justify;
|
||||
line-height: var(--text-indent);
|
||||
text-indent: var(--text-indent); }
|
||||
|
||||
p:not(:last-child) { margin-bottom: .1rem; }
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
font-size: 1.8rem;
|
||||
font-variant: small-caps;
|
||||
text-align: center;
|
||||
margin-bottom: 1rem; }
|
||||
|
||||
h2 {
|
||||
font-size: 1.4rem;
|
||||
margin: 1rem 0; }
|
||||
|
||||
html { margin-left: calc(100vw - 100%); }
|
||||
|
||||
body {
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
font-family: 'Roboto Condensed', Roboto, sans-serif;
|
||||
font-size: 1.1rem;
|
||||
margin: 0 auto;
|
||||
max-width: 960px;
|
||||
width: 98%; }
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
width: 360px; }
|
||||
|
||||
#logo text { fill: var(--text-color); }
|
||||
|
||||
#logo .logo {
|
||||
font-size: 2rem;
|
||||
font-variant-caps: small-caps;
|
||||
font-weight: bold; }
|
||||
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
#logo .logo { font-size: 2.082rem; } }
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
#logo .logo { font-size: 2rem; } }
|
||||
|
||||
#logo .under { font-size: .88rem; }
|
||||
|
||||
nav { margin-top: .5rem; }
|
||||
|
||||
nav a { font-variant: small-caps; }
|
||||
|
||||
nav h1 {
|
||||
color: var(--secondary-color);
|
||||
margin: 0; }
|
||||
|
||||
section { margin-top: 1rem; }
|
||||
|
||||
#overlay {
|
||||
align-items: center;
|
||||
background-color: var(--overlay-background-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
max-height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
visibility: hidden;
|
||||
width: 100%; }
|
||||
|
||||
#overlay video,
|
||||
#overlay audio,
|
||||
#overlay img {
|
||||
margin: auto;
|
||||
max-height: 100%;
|
||||
max-width: 86%;
|
||||
}
|
||||
|
||||
#overlay span {
|
||||
color: var(--background-color);
|
||||
text-shadow: 0 0 .3rem var(--secondary-color);
|
||||
}
|
||||
|
||||
table { overflow-y: scroll; width: 100%; }
|
||||
|
||||
tr { vertical-align: top; }
|
||||
|
||||
tr:hover { background-color: var(--primary-color); color: white; }
|
||||
|
||||
tr:hover a { color: white; }
|
||||
|
||||
th { text-align: left; }
|
||||
|
||||
th:nth-child(2),
|
||||
th:last-child { width: 1%; white-space: nowrap; }
|
||||
|
||||
th,
|
||||
td { line-break: strict; }
|
||||
|
||||
th:nth-child(2),
|
||||
td:nth-child(2) { padding: 0 1rem; }
|
||||
|
||||
td a { display: block; width: 100%; }
|
||||
|
||||
td a:hover { transition: none; }
|
||||
|
||||
td:nth-child(2),
|
||||
td:last-child { white-space: nowrap; }
|
||||
|
||||
footer {
|
||||
font-size: .8rem;
|
||||
text-align: center;
|
||||
padding: 1rem 0; }
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
header { display: block; }
|
||||
|
||||
#logo {
|
||||
margin: 0 auto;
|
||||
width: 100%; }
|
||||
|
||||
nav {
|
||||
width: 100%;
|
||||
text-align: center; } }
|
@ -1,56 +0,0 @@
|
||||
const video_formats = ["webm", "mp4"];
|
||||
const audio_formats = ["mp3", "flac", "opus", "ogg", "m4a"];
|
||||
const image_formats = ["jpg", "jpeg", "gif", "png", "bmp", "webp"];
|
||||
|
||||
const overlay = document.getElementById("overlay");
|
||||
let g_scale = 1;
|
||||
let g_volume = 1.0;
|
||||
|
||||
function mousescroll(e) {
|
||||
e.preventDefault();
|
||||
g_scale = Math.min(Math.max(0.25, g_scale + (e.deltaY * -0.001)), 4);
|
||||
e.target.style.transform = `scale(${g_scale})`;
|
||||
}
|
||||
|
||||
function onvolumechange(e) {
|
||||
g_volume = e.target.volume;
|
||||
}
|
||||
|
||||
const ext_filter = (ext, pathname) => pathname.toLowerCase().endsWith(ext);
|
||||
|
||||
function to_overlay(eltyp, pathname) {
|
||||
const el = document.createElement(eltyp);
|
||||
const el_label = document.createElement("span");
|
||||
el_label.textContent = decodeURI(pathname.substr(pathname.lastIndexOf("/") + 1));
|
||||
if (eltyp !== "audio") el.addEventListener('wheel', mousescroll);
|
||||
if (eltyp !== "img") {
|
||||
el.autoplay = el.controls = true;
|
||||
el.addEventListener("volumechange", onvolumechange);
|
||||
el.volume = g_volume;
|
||||
}
|
||||
el.src = pathname;
|
||||
overlay.appendChild(el);
|
||||
overlay.appendChild(el_label);
|
||||
overlay.style.visibility = "visible";
|
||||
}
|
||||
|
||||
document.getElementById("overlay").addEventListener("click", e => {
|
||||
e.target.firstChild.remove();
|
||||
e.target.firstChild.remove();
|
||||
e.target.style.visibility = "hidden";
|
||||
g_scale = 1;
|
||||
});
|
||||
|
||||
const file_links = Array.from(document.getElementsByTagName('tr')).slice(2).filter(e => e.lastChild.innerHTML != "DIR").map(l => l.firstChild.firstChild);
|
||||
|
||||
file_links.forEach(f => f.addEventListener('click', e => {
|
||||
const pathname = e.target.pathname;
|
||||
if (video_formats.some(ext => ext_filter(ext, pathname)))
|
||||
to_overlay("video", pathname);
|
||||
else if (audio_formats.some(ext => ext_filter(ext, pathname)))
|
||||
to_overlay("audio", pathname);
|
||||
else if (image_formats.some(ext => ext_filter(ext, pathname)))
|
||||
to_overlay("img", pathname);
|
||||
if (overlay.firstChild != null)
|
||||
e.preventDefault();
|
||||
}));
|
@ -1,2 +0,0 @@
|
||||
User-agent: *
|
||||
Disallow: /assets/
|
@ -1,44 +0,0 @@
|
||||
doctype html
|
||||
html(lang='en')
|
||||
head
|
||||
title Arav's dwelling / Files
|
||||
meta(charset='utf-8')
|
||||
meta(http-equiv='X-UA-Compatible' content='IE=edge')
|
||||
meta(name='viewport' content='width=device-width, initial-scale=1.0')
|
||||
meta(name='theme-color' content='#cd2682')
|
||||
meta(name='description' content='My file share.')
|
||||
link(rel='icon' type='image/svg+xml' href='/shared/img/favicon.svg' sizes='any')
|
||||
link(href='/assets/css/main.css' rel='stylesheet')
|
||||
script(src='/assets/js/main.js' defer)
|
||||
body
|
||||
header
|
||||
svg#logo(viewBox='0 -25 216 40')
|
||||
text.logo Arav's dwelling
|
||||
text.under(y='11') Welcome to my sacred place, wanderer
|
||||
nav
|
||||
a(href=main_site) Back to main website
|
||||
h1 Files
|
||||
section#files
|
||||
span#current-path!= current_path
|
||||
p Files: #{total_files} (#{total_files_size}); Directories: #{total_directories}.
|
||||
table
|
||||
thead
|
||||
tr
|
||||
th Name
|
||||
th Date
|
||||
th Size
|
||||
tbody
|
||||
tr
|
||||
td #[a(href="../") ../]
|
||||
each item in items
|
||||
tr
|
||||
td #[a(href=item.link)= item.name]
|
||||
td!= moment(item.datetime, clientTZ)
|
||||
td= item.size
|
||||
section#privacy
|
||||
h2 Privacy statements
|
||||
p I collect access logs that include access date and time, IP-address, User-Agent, referer URL that tells me where have you came from, request that you sent to me. In addition there are GeoIP information added based on your IP-address that includes country, region, and city for my convenience.
|
||||
p This site makes use of JavaScript purely for convenient functionality, like being able to watch video, listen to music, and look images in an overlay without the need to open a file in a new tab or return back.
|
||||
footer
|
||||
| 2017—2022 Arav <#[a(href='mailto:me@arav.top') me@arav.top]>
|
||||
div#overlay
|
@ -1,2 +0,0 @@
|
||||
exports.port = 32251;
|
||||
exports.host = "127.0.0.1";
|
@ -1,79 +0,0 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const uti = require("util");
|
||||
const exec = uti.promisify(require("child_process").exec);
|
||||
|
||||
const Koa = require("koa");
|
||||
const koaPug = require("koa-pug");
|
||||
const koaRouter = require("koa-router");
|
||||
const fetch = require("node-fetch");
|
||||
const moment = require("moment-timezone");
|
||||
|
||||
const config = require("./config");
|
||||
const util = require("../shared/util");
|
||||
|
||||
async function getRadioStatus() {
|
||||
try {
|
||||
let status = await fetch('http://radio.arav.home.arpa/status-json.xsl').then(r => r.json());
|
||||
return {
|
||||
server_start_iso8601: status.icestats.source.stream_start_iso8601,
|
||||
server_start_date: util.datetime(status.icestats.source.stream_start_iso8601, util.date_formats.post_date),
|
||||
song: `${status.icestats.source.artist} - ${status.icestats.source.title}`,
|
||||
listener_peak: status.icestats.source.listener_peak,
|
||||
listeners: status.icestats.source.listeners
|
||||
}
|
||||
} catch {
|
||||
return {
|
||||
server_start_iso8601: "n/a",
|
||||
server_start_date: "n/a",
|
||||
song: "n/a",
|
||||
listener_peak: "n/a",
|
||||
listeners: "n/a"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getLastPlayedSongs(count, tz) {
|
||||
try {
|
||||
const { stdout, _ } = await exec(`tail -n${count} /var/log/icecast/playlist.log | head -n-1 | cut -d"|" -f1,4`);
|
||||
let songs = stdout.trim().split("\n");
|
||||
for (let i = 0; i < songs.length; ++i) {
|
||||
let [t, s] = songs[i].split('|');
|
||||
t = moment(t, "DD/MMM/YYYY:HH:mm:ss ZZ").tz(tz).format("HH:mm");
|
||||
let song = s.split(' - ');
|
||||
songs[i] = { "start_time_local": t, "artist": song[0], "title": song[1] };
|
||||
}
|
||||
return songs;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function setRoutes() {
|
||||
return koaRouter().get('/', async ctx => {
|
||||
await ctx.render('index', {
|
||||
main_site: util.getServiceByHost(ctx.header.host),
|
||||
radio_status: await getRadioStatus(),
|
||||
last_songs: await getLastPlayedSongs(11, util.getClientTimezone(ctx))
|
||||
});
|
||||
})
|
||||
.get('/stats', async ctx => {
|
||||
ctx.body = await getRadioStatus();
|
||||
})
|
||||
.get('/lastsong', async ctx => {
|
||||
ctx.body = (await getLastPlayedSongs(2, util.getClientTimezone(ctx)))[0];
|
||||
});
|
||||
}
|
||||
|
||||
const app = new Koa();
|
||||
const pug = new koaPug({
|
||||
viewPath: path.join(__dirname, "views"),
|
||||
locals: {
|
||||
moment: util.datetime },
|
||||
app: app
|
||||
});
|
||||
|
||||
app.proxy = true;
|
||||
app
|
||||
.use(setRoutes().routes())
|
||||
.listen(config.port, config.host);
|
@ -1,154 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'Roboto Condensed';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('RobotoCondensed'), local('RobotoCondensed-Regular'),
|
||||
url(/shared/fonts/RobotoCondensed-Regular.ttf); }
|
||||
|
||||
:root {
|
||||
--background-color: #0a0a0a;
|
||||
--primary-color: #cd2682;
|
||||
--secondary-color: #9f2b68;
|
||||
--text-color: #f5f5f5;
|
||||
--text-indent: 1.6rem;
|
||||
scrollbar-color: var(--primary-color) var(--background-color); }
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--background-color: #f5f5f5;
|
||||
--primary-color: #9f2b68;
|
||||
--secondary-color: #cd2682;
|
||||
--text-color: #0a0a0a; } }
|
||||
|
||||
* { margin: 0; }
|
||||
|
||||
::selection {
|
||||
background-color: var(--secondary-color);
|
||||
color: var(--background-color); }
|
||||
|
||||
a,
|
||||
button {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none; }
|
||||
|
||||
a:hover,
|
||||
button:hover {
|
||||
color: var(--secondary-color);
|
||||
cursor: pointer;
|
||||
text-decoration: underline dotted;
|
||||
transition: .5s; }
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
font: inherit;
|
||||
padding: 0; }
|
||||
|
||||
p {
|
||||
text-align: justify;
|
||||
line-height: var(--text-indent);
|
||||
text-indent: var(--text-indent); }
|
||||
|
||||
p:not(:last-child) { margin-bottom: .1rem; }
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
font-size: 1.8rem;
|
||||
font-variant: small-caps;
|
||||
text-align: center;
|
||||
margin-bottom: 1rem; }
|
||||
|
||||
h2 {
|
||||
font-size: 1.4rem;
|
||||
margin: 1rem 0; }
|
||||
|
||||
small { font-size: .8rem; }
|
||||
|
||||
small.player-links a { margin: 0 .2rem; }
|
||||
|
||||
audio {
|
||||
background-color: var(--primary-color);
|
||||
box-shadow: 5px 5px var(--primary-color);
|
||||
width: 100%; }
|
||||
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
audio::-webkit-media-controls-panel {
|
||||
background-color: var(--secondary-color); }
|
||||
|
||||
audio { border-radius: 1.6rem; } }
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
audio { border-radius: 0; } }
|
||||
|
||||
html { margin-left: calc(100vw - 100%); }
|
||||
|
||||
body {
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
font-family: 'Roboto Condensed', Roboto, sans-serif;
|
||||
font-size: 1.1rem;
|
||||
margin: 0 auto;
|
||||
max-width: 960px;
|
||||
width: 98%; }
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
width: 360px; }
|
||||
|
||||
#logo text { fill: var(--text-color); }
|
||||
|
||||
#logo .logo {
|
||||
font-size: 2rem;
|
||||
font-variant-caps: small-caps;
|
||||
font-weight: bold; }
|
||||
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
#logo .logo { font-size: 2.082rem; } }
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
#logo .logo { font-size: 2rem; } }
|
||||
|
||||
#logo .under { font-size: .88rem; }
|
||||
|
||||
nav { margin-top: .5rem; }
|
||||
|
||||
nav a { font-variant: small-caps; }
|
||||
|
||||
nav h1 {
|
||||
color: var(--secondary-color);
|
||||
margin: 0; }
|
||||
|
||||
section { margin-top: 1rem; }
|
||||
|
||||
#last-played {
|
||||
margin: 0 auto;
|
||||
min-width: 80%;
|
||||
width: 80%; }
|
||||
|
||||
#last-played tbody tr {
|
||||
display: grid;
|
||||
gap: .5rem;
|
||||
grid-template-columns: 3rem 1fr 1fr; }
|
||||
|
||||
#last-played tbody tr td:nth-child(2) { text-align: right; }
|
||||
|
||||
footer {
|
||||
font-size: .8rem;
|
||||
text-align: center;
|
||||
padding: 1rem 0; }
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
header { display: block; }
|
||||
|
||||
#logo {
|
||||
margin: 0 auto;
|
||||
width: 100%; }
|
||||
|
||||
nav {
|
||||
width: 100%;
|
||||
text-align: center; } }
|
@ -1,9 +0,0 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1,Arav's dwelling / Radio
|
||||
http://radio.arav.top:8000/stream.ogg
|
||||
#EXTINF:-1,Arav's dwelling / Radio (HTTPS)
|
||||
https://radio.arav.top/live/stream.ogg
|
||||
#EXTINF:-1,Arav's dwelling / Radio on Tor
|
||||
http://wsmkgnmhmzqm7kyzv7jnzzafvgm7xlmlfvzhgorpapd5or2arnhuktqd.onion/live/stream.ogg
|
||||
#EXTINF:-1,Arav's dwelling / Radio on I2P
|
||||
http://radio.arav.i2p/live/stream.ogg
|
@ -1,48 +0,0 @@
|
||||
function $(id) { return document.getElementById(id); }
|
||||
|
||||
function updateRadioStatus() {
|
||||
fetch("/stats")
|
||||
.then(r => r.json())
|
||||
.then(r => {
|
||||
$("radio-status").innerHTML =
|
||||
`On-air since <time datetime="${r.server_start_iso8601}">${r.server_start_date}</time>`;
|
||||
$("radio-song").textContent = r.song;
|
||||
$("radio-listeners").textContent = r.listeners;
|
||||
$("radio-listener-peak").textContent = r.listener_peak;
|
||||
}).catch(() => {
|
||||
$("radio-status").textContent = "Radio is offline.";
|
||||
$("radio-song").textContent =
|
||||
$("radio-listeners").textContent =
|
||||
$("radio-listener-peak").textContent = "n/a";
|
||||
});
|
||||
}
|
||||
|
||||
function updateLastPlayedSong() {
|
||||
fetch('/lastsong')
|
||||
.then(r => r.json())
|
||||
.then(last_played => {
|
||||
let cur_artist = $('last-played').firstChild.lastChild.children[1].innerText;
|
||||
let cur_title = $('last-played').firstChild.lastChild.lastChild.innerText;
|
||||
|
||||
if (last_played.artist == cur_artist && last_played.title == cur_title)
|
||||
return;
|
||||
|
||||
$('last-played').firstChild.firstChild.remove();
|
||||
|
||||
let row = $('last-played').insertRow();
|
||||
let start_time = row.insertCell();
|
||||
start_time.appendChild(document.createTextNode(last_played.start_time_local));
|
||||
let artist_cell = row.insertCell();
|
||||
artist_cell.appendChild(document.createTextNode(last_played.artist));
|
||||
let title_cell = row.insertCell();
|
||||
title_cell.appendChild(document.createTextNode(last_played.title));
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("btn-update").addEventListener("click", () => {
|
||||
updateLastPlayedSong();
|
||||
updateRadioStatus();
|
||||
})
|
||||
|
||||
setInterval(updateRadioStatus, 45000);
|
||||
setInterval(updateLastPlayedSong, 45000);
|
@ -1,3 +0,0 @@
|
||||
User-agent: *
|
||||
Disallow: /assets/
|
||||
Disallow: /live/
|
@ -1,60 +0,0 @@
|
||||
mixin radioStatus(date, iso)
|
||||
if (date != "n/a")
|
||||
p #[span#radio-status On-air since #[time(datetime=iso)= date]]
|
||||
else
|
||||
p #[span#radio-status Radio is offline.]
|
||||
|
||||
doctype html
|
||||
html(lang='en')
|
||||
head
|
||||
title Arav's dwelling / Radio
|
||||
meta(charset='utf-8')
|
||||
meta(http-equiv='X-UA-Compatible' content='IE=edge')
|
||||
meta(name='viewport' content='width=device-width, initial-scale=1.0')
|
||||
meta(name='theme-color' content='#cd2682')
|
||||
meta(name='description' content='Internet-radio broadcasting from under my desk.')
|
||||
link(rel='icon' href='/shared/img/favicon.svg' sizes='any' type='image/svg+xml')
|
||||
link(href='/assets/css/main.css' rel='stylesheet')
|
||||
script(src='/assets/js/main.js' defer)
|
||||
body
|
||||
header
|
||||
svg#logo(viewBox='0 -25 216 40')
|
||||
text.logo Arav's dwelling
|
||||
text.under(y='11') Welcome to my sacred place, wanderer
|
||||
nav
|
||||
a(href=main_site) Back to main website
|
||||
h1 Radio
|
||||
section
|
||||
small.player-links
|
||||
a(href='/filelist') filelist
|
||||
a(href='/playlist') playlist (.m3u)
|
||||
a(href='/live/stream.ogg') direct link
|
||||
a(href='http://radio.arav.top:8000/stream.ogg') direct link (http)
|
||||
a(href='http://wsmkgnmhmzqm7kyzv7jnzzafvgm7xlmlfvzhgorpapd5or2arnhuktqd.onion/live/stream.ogg') direct link (Tor)
|
||||
a(href='http://radio.arav.i2p/live/stream.ogg') direct link (I2P)
|
||||
a(href='https://dir.xiph.org/search?q=arav\'s+dwelling') Xiph
|
||||
| OGG 128 Kb/s
|
||||
audio(preload='none' controls)
|
||||
source(src='/live/stream.ogg' type='audio/ogg')
|
||||
| Your browser doesn't support an audio element, it's sad... But you always can take the #[a(href='/playlist') playlist]!
|
||||
+radioStatus(radio_status.server_start_date, radio_status.server_start_iso8601)
|
||||
p Now playing: #[span#radio-song= radio_status.song]
|
||||
p Current/peak listeners: #[span#radio-listeners= radio_status.listeners] / #[span#radio-listener-peak= radio_status.listener_peak]
|
||||
p
|
||||
small Notice: information updates every 45 seconds. But you can #[button(id='btn-update') update] it forcibly.
|
||||
if (last_songs)
|
||||
section
|
||||
h2 Last 10 songs
|
||||
table#last-played
|
||||
each song in last_songs
|
||||
tr
|
||||
td= song.start_time_local
|
||||
td= song.artist
|
||||
td= song.title
|
||||
section
|
||||
p The largest number of simultaneous listeners was #[b 7] at #[time(datetime='2022-02-19') 19 February 2022], and the song was "Röyksopp - 49 Percent".
|
||||
section
|
||||
h2 Privacy statements
|
||||
p Logs are collected and include access date and time, IP-address, User-Agent, referer URL, request. This website makes use of JavaScript to update a radio status and last 10 songs list.
|
||||
footer
|
||||
| 2017—2022 Arav <#[a(href='mailto:me@arav.top') me@arav.top]>
|
Loading…
Reference in New Issue
Block a user