From f23c6ed4f84055551b459d235c4a675faf017cea Mon Sep 17 00:00:00 2001 From: Nguyễn Gia Phong Date: Wed, 1 Jun 2022 02:09:01 +0900 Subject: Draft basic CBZ rendering --- main.go | 81 +++++++++++++++- static/favicon.svg | 53 +++++++++++ static/style.css | 250 ------------------------------------------------- templates/archive.html | 19 ++++ templates/index.html | 1 + 5 files changed, 153 insertions(+), 251 deletions(-) create mode 100644 static/favicon.svg delete mode 100644 static/style.css create mode 100644 templates/archive.html diff --git a/main.go b/main.go index 656b816..4fa807b 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,34 @@ +// Server entry point +// Copyright (C) 2022 Nguyễn Gia Phong +// +// This file is part of Phylactery. +// +// Phylactery is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Phylactery is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Phylactery. If not, see . + package main import ( + "archive/zip" "embed" "html/template" "log" + "io" "net/http" "os" + "path" + "strconv" + "strings" ) //go:embed static/* @@ -14,14 +37,70 @@ var static embed.FS //go:embed templates/*.html var templates embed.FS +type Page struct { + Index int + Name string +} + +type Archive struct { + Path string + Title string + Entries []Page +} + func main() { http.Handle("/static/", http.FileServer(http.FS(static))) t, err := template.ParseFS(templates, "templates/*.html") if err != nil { log.Fatal(err) } + lib := os.Getenv("PHYLACTERY_LIBRARY") http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - t.ExecuteTemplate(w, "index.html", "Phylactery") + p := path.Clean(lib + r.URL.Path) + stat, err := os.Stat(p) + if err != nil { + http.NotFound(w, r) + return + } + + if stat.IsDir() { + // TODO + } + + // TODO: LRU caching + cbz, err := zip.OpenReader(p) + if err != nil { + http.Error(w, "invalid cbz", 406) + return + } + defer cbz.Close() + + r.ParseForm() + if entry, isImage := r.Form["entry"]; isImage { + i, err := strconv.Atoi(entry[0]) + if err != nil || i < 0 || i >= len(cbz.File) { + http.NotFound(w, r) + return + } + image, _ := cbz.File[i].Open() + defer image.Close() + io.Copy(w, image) + return + } + + var pages []Page + for i, f := range cbz.File { + image, _ := cbz.File[i].Open() + defer image.Close() + buf := make([]byte, 512) + n, _ := image.Read(buf) + mime := http.DetectContentType(buf[:n]) + if strings.HasPrefix(mime, "image/") { + pages = append(pages, Page{ i, f.Name }) + } + } + archive := Archive{ r.URL.Path, stat.Name(), pages } + t.ExecuteTemplate(w, "archive.html", archive) }) addr := os.Getenv("PHYLACTERY_ADDRESS") diff --git a/static/favicon.svg b/static/favicon.svg new file mode 100644 index 0000000..2305a95 --- /dev/null +++ b/static/favicon.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + scroll + 2007-11-08T21:26:16 + Scroll of paper, white filled. + https://openclipart.org/detail/8032/scroll-by-kelan + + + kelan + + + + + paper + scroll + white + + + + + + + + + + + \ No newline at end of file diff --git a/static/style.css b/static/style.css deleted file mode 100644 index d7bea79..0000000 --- a/static/style.css +++ /dev/null @@ -1,250 +0,0 @@ -/* Variables */ -:root { - --black: #1c1b19; - --red: #ef2f27; - --green: #519f50; - --yellow: #fbb829; - --blue: #2c78bf; - --magenta: #e02c6d; - --cyan: #0aaeb3; - --white: #d0bfa1; - --bright-black: #918175; - --bright-red: #f75341; - --bright-green: #98bc37; - --bright-yellow: #fed06e; - --bright-blue: #68a8e4; - --bright-magenta: #ff5c8f; - --bright-cyan: #53fde9; - --bright-white: #fce8c3; - - --block-bg: var(--black); - --fade-fg: var(--bright-black); - --link-fg: var(--green); - --overlay-bg: #8881; - --text-bg: #121212; - --text-fg: var(--bright-white); -} - -@media (prefers-color-scheme: light) { - :root { - --block-bg: #eeeeec; - --fade-fg: #888a85; - --link-fg: #436e58; - --text-bg: #ffffff; - --text-fg: #2e3436; - } -} - -/* Default font and layout */ -html { - background-color: var(--text-bg); - box-sizing: border-box; - color: var(--text-fg); - font-size: min(max(100%, 2vw), 150%); - margin: auto; - max-width: 36rem; - scrollbar-color: var(--fade-fg) var(--overlay-bg); -} - -body { margin: 0 1rem } - -.franklin-content .row { display: block } - -/* Text geometry */ -p, details { - hyphens: auto; - line-height: 1.4rem; - text-align: justify; -} - -/* Titles */ -.franklin-content h1 a, -.franklin-content h2 a, -.franklin-content h3 a, -.franklin-content h4 a, -.franklin-content h5 a, -.franklin-content h6 a { - color: var(--text-fg); -} - -.franklin-content h1 a:hover, -.franklin-content h2 a:hover, -.franklin-content h3 a:hover, -.franklin-content h4 a:hover, -.franklin-content h5 a:hover, -.franklin-content h6 a:hover { - text-decoration: none; -} - -.franklin-toc ol ol { - list-style-type: lower-alpha; -} - -/* General formatting */ -.franklin-content li p { margin: 0 } - -.franklin-content a { - color: var(--link-fg); - text-decoration: none; -} - -.franklin-content a:hover { - text-decoration: underline; - } - -/* Hyperrefs and footnotes */ -.franklin-content .bibref a, -.franklin-content .eqref a { color: var(--link-fg) } - -.franklin-content .fndef { - border: none; - margin: 1ex 0; -} -.franklin-content .fndef tr { text-align: left } -.franklin-content .fndef td { padding: 0 } -.franklin-content .fndef td, .franklin-content sup { font-size: 80% } -.franklin-content .fndef td.fndef-backref { padding-left: 0 } -.franklin-content .fndef td.fndef-content { padding-left: 1ch } - -/* Images */ -.franklin-content img { - display: block; - margin: auto; - max-width: 100%; -} - -/* KaTeX */ -.katex { font-size: 1em !important } - -/* Boxes */ -.franklin-content blockquote, .note { - margin: 0 -1rem; - padding-bottom: 1ex; - padding-left: 0.75rem; - padding-right: 1rem; - padding-top: 1ex; -} -.franklin-content blockquote p, .note p { margin: 1ex 0 } -.note p:first-child { font-weight: bold } -.franklin-content blockquote { - background: var(--overlay-bg); - border-left: 0.25rem solid #8884; -} -.note { - background-color: #51affe25; - border-left: 0.25rem solid var(--blue); -} - -/* Header */ -header { - margin: 1.5rem -0.5rem; - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; -} - -header a { - border-bottom: solid; - color: var(--link-fg); - font-weight: bold; - margin: 0 0.5rem; - text-decoration: none; - transition: color 0.3s ease; -} -header a:hover { color: var(--text-fg) } - -nav, nav li { display: inline-block } -nav ul { margin: 0 } - -footer, .tags, .right { - color: var(--fade-fg); - font-size: 80%; -} - -footer { - margin-top: 1.5rem; - margin-bottom: 2rem; -} - -footer a, .tags a { - color: var(--fade-fg)!important; - text-decoration: underline!important; -} - -.nowrap { display: inline-block } -.tags { float: left } -.right { - float: right; - margin-left: auto; -} - -/* Table */ -table { - border-bottom: 0.15em solid var(--text-fg); - border-collapse: collapse; - border-top: 0.15em solid var(--text-fg); - line-height: 1em; - margin-bottom: 1.5em; - margin-left: auto; - margin-right: auto; - text-align: center; -} - -tr:first-of-type > th { border-bottom: 0.08em solid var(--text-fg) } -tr, th, td { padding: 0.5em } - -/* highlight.js */ -code, .hljs { - background-color: var(--block-bg); - font-size: inherit; - padding: 0.1em 0.2em; -} - -.hljs, .comment pre > code { - display: block; - line-height: 1.45em; - overflow-x: auto; -} - -.hljs-built_in .hljs-name, .hljs-title, .hljs-type { color: var(--cyan) } -.hljs-code, .hljs-selector-class { color: var(--bright-blue) } -.hljs-comment, .hljs-deletion, .hljs-meta { color: var(--fade-fg) } -.hljs-comment, .hljs-emphasis { font-style: italic; } -.hljs-string { color: var(--bright-green) } -.hljs-strong { font-weight: bold; } - -.hljs-bullet, .hljs-quote, .hljs-link, .hljs-number, -.hljs-regexp, .hljs-literal { color: var(--bright-magenta) } - -.hljs-keyword, .hljs-selector-tag, .hljs-section, -.hljs-attribute, .hljs-variable { color: var(--red) } - -.hljs-subst, .hljs-symbol, .hljs-selector-id, .hljs-selector-attr, -.hljs-selector-pseudo, .hljs-template-tag, .hljs-template-variable, -.hljs-addition { color: var(--red) } - -.comment { - background-color: var(--overlay-bg); - clear: both; - margin: 1ex 0; - overflow: hidden; - padding: 0 1rem; -} - -.openring { - display: flex; - flex-wrap: wrap; - margin: -0.5rem; - margin-bottom: 0; -} -.openring h3 { margin: 0 0 1ex } -.openring article { - background: var(--overlay-bg); - display: flex; - flex-direction: column; - flex: 1 1 0; - margin: 1ex; - min-width: 12rem; - padding: 1ex; -} diff --git a/templates/archive.html b/templates/archive.html new file mode 100644 index 0000000..d3d8e0b --- /dev/null +++ b/templates/archive.html @@ -0,0 +1,19 @@ + + + + + +{{.Title}} + + +{{range .Entries}} +{{.Name}}{{end}} + + diff --git a/templates/index.html b/templates/index.html index 39785aa..67f96fb 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3,6 +3,7 @@ + {{.}} -- cgit 1.4.1