diff --git a/README.md b/README.md index fb0d31f..9a741d3 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,12 @@ Then to actually run: bash tor_prebuilt.sh ``` +Make sure to set a master password! See `.env.example`. Enter in the master password at /password to get the current day and the next day's password. + # Tips ## Adding media -Add it to the relevant static directory (`/static_assets/anime_assets`, `/static_assets/manga_assets`, or `/static_assets/music_assets`), and create an entry for it in `host_info.json`. +Add it to the relevant static directory (`/static_assets/anime_assets`, `/static_assets/manga_assets`, or `/static_assets/music_assets`), and create an entry for it in `host_info.json`. See `host_info.json.example` for an example. ## Hosting Multiple TOR Hidden Services If you are running multiple TOR hidden services, you will need to modify the [.torrc file](https://stackoverflow.com/questions/14321214/how-to-run-multiple-tor-processes-at-once-with-different-exit-ips#18895491). diff --git a/build.ts b/build.ts index 6f68282..80f228f 100644 --- a/build.ts +++ b/build.ts @@ -9,6 +9,10 @@ import _host_info from './host_info.json'; interface Listing { name: string; type: "anime" | "manga" | "music"; + favourites: { + listing: boolean; //whether to mark entire listing as favourite + chapters: string[]; //favourite chapters + }; //marked as not optional here, but in the actual host_info.json file, it is optional } interface DirectoryVars { @@ -33,10 +37,23 @@ interface MangaVars { 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" || listing?.type === "music")); +const listings: Listing[] = _host_info.listings.map( + (listing: any) => + //add empty "favourites" if not present in the json + listing.favourites ? listing : { + ...listing, + favourites: { + listing: false, + chapters: [] + } + } +).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 builder: Builder = new Builder("/build");; +let builder: Builder = new Builder("/build"); //static page builder.serve_static_folder("static"); @@ -60,6 +77,7 @@ let music_serve_paths: string[] = []; let music_vars: MusicVars[] = []; let songs: string[] = []; +let manga_pages_count: number = 0; for (let i = 0; i < listings.length; i++) { const listing: Listing = listings[i]; @@ -85,6 +103,7 @@ for (let i = 0; i < listings.length; i++) { const chapter: string = chapters[j]; manga_serve_paths.push(`/${listing.type}/${listing.name}/${chapter}`); const images: string[] = readdirSync(path.join(__dirname, `/static_assets/${listing.type}_assets/${listing.name}/${chapter}`), { withFileTypes: true }).map((d) => d.name); + manga_pages_count += images.length; manga_vars.push({ listing, chapter, @@ -113,13 +132,34 @@ builder.serve_templates(renderer, anime_serve_paths, "anime", anime_vars); builder.serve_templates(renderer, manga_serve_paths, "manga", manga_vars); builder.serve_templates(renderer, music_serve_paths, "music", music_vars); +builder.serve_template(renderer, "/stats", "stats", { + manga_series_count: listings.filter((l) => l.type === "manga").length, + manga_chapters_count: manga_serve_paths.length, + manga_pages_count, + anime_series_count: listings.filter((l) => l.type === "anime").length, + anime_episodes_count: anime_serve_paths.length, + artists_count: listings.filter((l) => l.type === "music").length, + songs_count: songs.length, +}); + builder.serve_template(renderer, "/player", "player", { songs, artists: listings.filter((l) => l.type === "music").map( (l) => ( { name: l.name, - songs: songs.filter((s) => s.startsWith(`${l.name}/`)).map((song) => song.slice(`${l.name}/`.length)), + sanitized_name: l.name.replaceAll("\"", "\\\""), + songs: songs.filter((s) => s.startsWith(`${l.name}/`)).map( + (song) => ( + { + name: song.slice(`${l.name}/`.length), + //I don't think " can be in file names... but just in case + sanitized_name: song.slice(`${l.name}/`.length).replaceAll("\"", "\\\""), + favourite: l.favourites.chapters.includes(song.slice(`${l.name}/`.length)), + } + ) + ), + favourite: l.favourites.listing, } ) ), diff --git a/host_info.json.example b/host_info.json.example new file mode 100644 index 0000000..c8ebb26 --- /dev/null +++ b/host_info.json.example @@ -0,0 +1,44 @@ +{ + "listings": [ + { + "name": "senpai-wa-otokonoko", + "type": "manga", + "favourites": { + "listing": true, + "chapters": ["c001"] + } + }, + { + "name": "shiitake-simulation", + "type": "manga" + }, + { + "name": "bocchi-the-boulder", + "type": "anime", + "favourites": { + "listing": true, + "chapters": [] + } + }, + { + "name": "yoroshiku", + "type": "music" + }, + { + "name": "not-buna", + "type": "music", + "favourites": { + "listing": false, + "chapters": ["aira"] + } + }, + { + "name": "arizona-philips", + "type": "music", + "favourites": { + "listing": true, + "chapters": [] + } + } + ] +} \ No newline at end of file diff --git a/ryuji.ts b/ryuji.ts index 63df44d..4e1e035 100644 --- a/ryuji.ts +++ b/ryuji.ts @@ -1,6 +1,6 @@ import { readFileSync } from 'fs'; -export const SYNTAX_REGEX = /\[\[ [a-zA-Z0-9.:/\-_!]+ \]\]/g; +export const SYNTAX_REGEX = /\[\[ [a-zA-Z0-9.:/\*\-_!]+ \]\]/g; export type file_extension = `.${string}`; @@ -185,12 +185,21 @@ export class Renderer { } else { //compare with second var let var_name2: string = exp_parts[2]; + let if_in: boolean = false; let if_not: boolean = false; + //*! is valid + if (var_name2.startsWith("*")) { + var_name2 = var_name2.slice(1, var_name2.length); + if_in = true; + } if (var_name2.startsWith("!")) { var_name2 = var_name2.slice(1, var_name2.length); if_not = true; } let var_value2 = Renderer.get_var(var_name2, vars); + if (if_in) { + var_value2 = var_value2.find((ele) => ele === var_value); + } if (if_not) { //make sure the two compared variables are NOT equal if (var_value !== var_value2) { diff --git a/templates/components/chapter-listing.html b/templates/components/chapter-listing.html index d3da51e..a9ee0fa 100644 --- a/templates/components/chapter-listing.html +++ b/templates/components/chapter-listing.html @@ -1 +1 @@ -
  • [[ chapter ]]
  • \ No newline at end of file +
  • [[ if:chapter:*listing.favourites.chapters ]]★[[ endif ]][[ chapter ]]
  • \ No newline at end of file diff --git a/templates/components/listing.html b/templates/components/listing.html index 1e2c8cb..f3ddd8c 100644 --- a/templates/components/listing.html +++ b/templates/components/listing.html @@ -1 +1 @@ -
  • [[ listing.name ]] ([[ listing.type ]])
  • \ No newline at end of file +
  • [[ if:listing.favourites ]][[ if:listing.favourites.listing ]]★[[ endif ]][[ endif ]][[ listing.name ]] ([[ listing.type ]])
  • \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index ae658c6..a0634e1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,11 +4,13 @@ these r not the droids you u looking 4 - +
    + Player + - + Stats +
    [[ for:artists:artist ]]
    - - -
    + + +
    [[ for:artist.songs:song ]] - - + + [[ endfor ]]
    @@ -81,15 +85,15 @@ }); //show filters toggle const show_filters = document.getElementById("show-filters"); - function filter_toggle() { + function filter_check() { if (show_filters.checked) { document.getElementById("filters-container").style.display = "block"; } else { document.getElementById("filters-container").style.display = "none"; } } - show_filters.onchange = filter_toggle; - filter_toggle(); + show_filters.onchange = filter_check; + filter_check(); //artist and artist song filter toggle function artist_filter_toggle(artist) { document.querySelectorAll(`#${artist}-song-filter > input[type=\"checkbox\"]`).forEach((c) => { @@ -97,8 +101,8 @@ c.onchange(); }); } - function artist_song_filter_toggle(artist, song) { - playable_songs = songs.filter((song) => document.getElementById(`${song.replace("/", "-")}-checkbox`).checked); + function update_playable_songs() { + playable_songs = songs.filter((song) => document.getElementById(`${song.replace("/", "-").replaceAll("\"", "\\\"")}-checkbox`).checked); } function filter_select_all() { document.querySelectorAll(".artist-filter > input[type=\"checkbox\"]").forEach((c) => { diff --git a/templates/stats.html b/templates/stats.html new file mode 100644 index 0000000..b981cc5 --- /dev/null +++ b/templates/stats.html @@ -0,0 +1,22 @@ + + + + + + stats + + +
    + Front page +
    +

    Manga series: [[ manga_series_count ]]

    +

    Manga chapters: [[ manga_chapters_count ]]

    +

    Manga pages: [[ manga_pages_count ]]

    +

    Anime series: [[ anime_series_count ]]

    +

    Anime episodes: [[ anime_episodes_count ]]

    +

    Music Artists: [[ artists_count ]]

    +

    Songs: [[ songs_count ]]

    +
    +
    + +