music draft

This commit is contained in:
jetstream0
2023-11-02 09:14:23 +00:00
parent e85193dcb4
commit 63cac1f0c5
5 changed files with 69 additions and 8 deletions

View File

@@ -1,4 +1,4 @@
The most legalest private file (specifically manga and anime) hosting ever, on TOR. Includes a manga viewer. Nothing fancy. Uses HTTP Basic Authentication with daily rotating password derived from a master password. The most legalest private file (specifically for manga, anime, music) hosting ever, on TOR. Includes a manga viewer. Nothing fancy. Uses HTTP Basic Authentication with daily rotating password derived from a master password.
Most of the code is a modification of [hedgeblog](https://github.com/jetstream0/hedgeblog), albeit with some pretty significant modifications in places (templates, host.ts, build.ts, saki.ts). Most of the code is a modification of [hedgeblog](https://github.com/jetstream0/hedgeblog), albeit with some pretty significant modifications in places (templates, host.ts, build.ts, saki.ts).

View File

@@ -8,7 +8,7 @@ import _host_info from './host_info.json';
interface Listing { interface Listing {
name: string; name: string;
type: "anime" | "manga"; type: "anime" | "manga" | "music";
} }
interface DirectoryVars { interface DirectoryVars {
@@ -23,6 +23,8 @@ interface AnimeVars {
prev_chapter?: string | boolean; prev_chapter?: string | boolean;
} }
type MusicVars = AnimeVars;
interface MangaVars { interface MangaVars {
listing: Listing; listing: Listing;
chapter: string; chapter: string;
@@ -31,7 +33,7 @@ interface MangaVars {
prev_chapter?: string | boolean; prev_chapter?: string | boolean;
} }
const listings: Listing[] = _host_info.listings.filter((listing: any): listing is Listing => typeof listing.name === "string" && (listing?.type === "anime" || listing?.type === "manga")); const listings: Listing[] = _host_info.listings.filter((listing: any): listing is Listing => typeof listing.name === "string" && (listing?.type === "anime" || listing?.type === "manga" || listing?.type === "music"));
let renderer: Renderer = new Renderer("templates", "components"); let renderer: Renderer = new Renderer("templates", "components");
let builder: Builder; let builder: Builder;
@@ -61,10 +63,13 @@ let anime_vars: AnimeVars[] = [];
let manga_serve_paths: string[] = []; let manga_serve_paths: string[] = [];
let manga_vars: MangaVars[] = []; let manga_vars: MangaVars[] = [];
let music_serve_paths: string[] = [];
let music_vars: MusicVars[] = [];
for (let i = 0; i < listings.length; i++) { for (let i = 0; i < listings.length; i++) {
const listing: Listing = listings[i]; const listing: Listing = listings[i];
directory_serve_paths.push(`/${listing.type}/${listing.name}`); directory_serve_paths.push(`/${listing.type}/${listing.name}`);
const chapters: string[] = readdirSync(path.join(__dirname, `/static/${listing.type}_assets/${listing.name}`), { withFileTypes: true }).map((d) => d.name.replace(".mp4", "")); const chapters: string[] = readdirSync(path.join(__dirname, `/static/${listing.type}_assets/${listing.name}`), { withFileTypes: true }).map((d) => d.name.replace(".mp4", "").replace(".mp3", ""));
directory_vars.push({ directory_vars.push({
listing, listing,
chapters, chapters,
@@ -93,9 +98,21 @@ for (let i = 0; i < listings.length; i++) {
prev_chapter: j > 0 ? chapters[j - 1] : false, prev_chapter: j > 0 ? chapters[j - 1] : false,
}); });
} }
} else if (listing.type === "music") {
for (let j = 0; j < chapters.length; j++) {
const chapter: string = chapters[j];
music_serve_paths.push(`/${listing.type}/${listing.name}/${chapter}`);
music_vars.push({
listing,
chapter,
next_chapter: chapters[j + 1] ? chapters[j + 1] : false,
prev_chapter: j > 0 ? chapters[j - 1] : false,
});
}
} }
} }
builder.serve_templates(renderer, directory_serve_paths, "directory", directory_vars); builder.serve_templates(renderer, directory_serve_paths, "directory", directory_vars);
builder.serve_templates(renderer, anime_serve_paths, "anime", anime_vars); builder.serve_templates(renderer, anime_serve_paths, "anime", anime_vars);
builder.serve_templates(renderer, manga_serve_paths, "manga", manga_vars); builder.serve_templates(renderer, manga_serve_paths, "manga", manga_vars);
builder.serve_templates(renderer, music_serve_paths, "music", music_vars);

18
host.ts
View File

@@ -19,10 +19,19 @@ const stream_chunk_size: number = 2 * 1024 * 1024; //2 MiB
createServer((req, res) => { createServer((req, res) => {
const todays_password: string = get_password(); const todays_password: string = get_password();
let req_path: string; let req_path: string;
if (req.url.includes("..")) {
//nice try
//bad request
res.writeHead(400);
//write file
res.write("400");
//end response
return res.end();
}
if (!req.url.includes(".")) { if (!req.url.includes(".")) {
req_path = path.join(__dirname, "build", req.url, "index.html"); req_path = path.join(__dirname, "build", decodeURI(req.url), "index.html");
} else { } else {
req_path = path.join(__dirname, "build", req.url); req_path = path.join(__dirname, "build", decodeURI(req.url));
} }
const url_obj = new URL(req.url, `http://${req.headers.host}`); const url_obj = new URL(req.url, `http://${req.headers.host}`);
//check for auth //check for auth
@@ -56,7 +65,7 @@ createServer((req, res) => {
return res.end(); return res.end();
} }
//set content type //set content type
let non_utf8_content_types: string[] = ["image/png", "image/gif", "image/jpeg", "video/mp4"]; let non_utf8_content_types: string[] = ["image/png", "image/gif", "image/jpeg", "audio/mpeg", "video/mp4"];
let content_type: string; let content_type: string;
switch (req_path.split(".")[1]) { switch (req_path.split(".")[1]) {
case "html": case "html":
@@ -82,6 +91,9 @@ createServer((req, res) => {
case "jpg": case "jpg":
content_type = "image/jpeg"; content_type = "image/jpeg";
break; break;
case "mp3":
content_type = "audio/mpeg";
break;
case "mp4": case "mp4":
content_type = "video/mp4"; content_type = "video/mp4";
break; break;

View File

@@ -13,7 +13,7 @@
<div> <div>
<a href="/">Front page</a> <a href="/">Front page</a>
<ul> <ul>
<!-- called chapters, but both anime and manga will use this --> <!-- called chapters, but anime, manga, music will all use this -->
[[ for:chapters:chapter ]] [[ for:chapters:chapter ]]
[[ component:chapter-listing ]] [[ component:chapter-listing ]]
[[ endfor ]] [[ endfor ]]

32
templates/music.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>listening to [[ listing.name ]]</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.music {
margin: 25px;
}
</style>
</head>
<body>
[[ component:return ]]
<div id="main">
<div class="music">
<h2 style="display: inline-block;">[[ listing.name ]] [[ chapter ]]</h2>
<br>
<audio controls>
<source src="/music_assets/[[ listing.name ]]/[[ chapter ]].mp3" type="audio/mpeg">
</audio>
[[ component:nav ]] <!-- id: nav -->
</div>
</div>
</body>
</html>