Compare commits
11 Commits
Author | SHA1 | Date |
---|---|---|
Alexander Andreev | df3ea75ca9 | |
Alexander Andreev | cbe0292e4c | |
Alexander Andreev | d6463e81e8 | |
Alexander Andreev | 99e39fc6c1 | |
Alexander Andreev | 5cc9b12030 | |
Alexander Andreev | 8b39e60a01 | |
Alexander Andreev | c06eaecbfc | |
Alexander Andreev | f23e4d713b | |
Alexander Andreev | 1a5d32f1b9 | |
Alexander Andreev | 775eef657e | |
Alexander Andreev | 06961fc7c4 |
15
Makefile
15
Makefile
|
@ -8,17 +8,18 @@ PREFIX:=/usr/local
|
|||
|
||||
VERSION=23.32.0
|
||||
|
||||
FLAGS=-buildmode=pie -modcacherw -mod=readonly -trimpath
|
||||
LDFLAGS=-ldflags "-s -w -X main.version=${VERSION}" -tags osusergo,netgo
|
||||
|
||||
all: web/*.jade.go ${TARGET}
|
||||
.PHONY: run install uninstall clean
|
||||
|
||||
.PHONY: ${TARGET}
|
||||
|
||||
${TARGET}:
|
||||
go build -o bin/$@ ${LDFLAGS} cmd/$@/main.go
|
||||
${TARGET}: web/*.jade.go
|
||||
go build -o bin/$@ ${LDFLAGS} ${FLAGS} cmd/$@/main.go
|
||||
|
||||
web/*.jade.go: web/templates/*.jade
|
||||
ifeq (,$(wildcard $(shell go env GOPATH)/bin/jade))
|
||||
go install github.com/Joker/jade/cmd/jade@latest
|
||||
endif
|
||||
go generate web/web.go
|
||||
|
||||
run:
|
||||
|
@ -33,3 +34,7 @@ uninstall:
|
|||
rm ${DESTDIR}${PREFIX}/bin/${TARGET}
|
||||
|
||||
rm ${DESTDIR}/${SYSDDIR}/${TARGET}.service
|
||||
|
||||
clean:
|
||||
rm -f web/*.jade.go
|
||||
go clean
|
2
go.mod
2
go.mod
|
@ -2,4 +2,4 @@ module dwelling-files
|
|||
|
||||
go 1.16
|
||||
|
||||
require git.arav.su/Arav/httpr v0.3.1
|
||||
require git.arav.su/Arav/httpr v0.3.2
|
||||
|
|
4
go.sum
4
go.sum
|
@ -1,2 +1,2 @@
|
|||
git.arav.su/Arav/httpr v0.3.1 h1:8ba90SJ4XYUWfIlC3V0Zuw3+CcOb9IYVkOZ/2mB9JO0=
|
||||
git.arav.su/Arav/httpr v0.3.1/go.mod h1:z0SVYwe5dBReeVuFU9QH2PmBxICJwchxqY5OfZbeVzU=
|
||||
git.arav.su/Arav/httpr v0.3.2 h1:a+ifu+9+FnQe6p/Kd4kgTDKAFN6zBOJjBTMjbAuHxVk=
|
||||
git.arav.su/Arav/httpr v0.3.2/go.mod h1:z0SVYwe5dBReeVuFU9QH2PmBxICJwchxqY5OfZbeVzU=
|
||||
|
|
|
@ -50,7 +50,7 @@ func (h *FilesHandlers) Index(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func (h *FilesHandlers) File(w http.ResponseWriter, r *http.Request) {
|
||||
if h.noFileHandling {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
Error(w, http.StatusServiceUnavailable, "File handling is turned off.", "", r.Referer())
|
||||
return
|
||||
}
|
||||
r.URL.Path = httpr.Param(r, "filepath")
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
const FileDateFormat = "2006-01-02 15:04:05 MST"
|
||||
|
||||
type DirStats struct {
|
||||
type DirStat struct {
|
||||
Files int64
|
||||
FilesSize string
|
||||
Directories int64
|
||||
|
@ -22,16 +22,16 @@ type DirEntry struct {
|
|||
Size string
|
||||
}
|
||||
|
||||
func ScanDirectory(path, urlBase string) (entries []DirEntry, stats DirStats, err error) {
|
||||
var dirEntries []DirEntry = make([]DirEntry, 0)
|
||||
var fileEntries []DirEntry = make([]DirEntry, 0)
|
||||
var totalFilesSize int64 = 0
|
||||
|
||||
func ScanDirectory(path, urlBase string) (entries []DirEntry, stats DirStat, err error) {
|
||||
dir, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var dirEntries []DirEntry = make([]DirEntry, 0)
|
||||
var fileEntries []DirEntry = make([]DirEntry, 0)
|
||||
var totalFilesSize int64 = 0
|
||||
|
||||
for _, ent := range dir {
|
||||
entry, _ := ent.Info()
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package files
|
||||
|
||||
import "testing"
|
||||
|
||||
const path = "/mnt/data/music/Various"
|
||||
const urlBase = "/srv/ftp/"
|
||||
|
||||
func BenchmarkScanDirectory(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
/*e, _, _ :=*/ ScanDirectory(path, urlBase)
|
||||
// b.Log(e[len(e)-1], len(e))
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#error {
|
||||
font-size: 3.5rem;
|
||||
line-height: 5rem;
|
||||
text-align: center;
|
||||
margin: 6rem 0; }
|
||||
|
||||
#error h1 { font-size: 8rem; }
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
::placeholder { color: var(--primary-color); }
|
||||
|
||||
.hidden { display: none; }
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none; }
|
||||
|
@ -58,8 +60,6 @@ h2 {
|
|||
font-size: 1.4rem;
|
||||
margin: 1rem 0; }
|
||||
|
||||
.hidden { display: none; }
|
||||
|
||||
html { margin-left: calc(100vw - 100%); }
|
||||
|
||||
body {
|
||||
|
@ -69,6 +69,7 @@ body {
|
|||
font-size: 1.1rem;
|
||||
margin: 0 auto;
|
||||
max-width: 960px;
|
||||
min-height: 100vh;
|
||||
width: 98%; }
|
||||
|
||||
header {
|
||||
|
@ -76,24 +77,22 @@ header {
|
|||
flex-wrap: wrap;
|
||||
justify-content: space-between; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
width: 360px; }
|
||||
header svg { width: 360px; }
|
||||
|
||||
#logo text { fill: var(--text-color); }
|
||||
header svg text { fill: var(--text-color); }
|
||||
|
||||
#logo .logo {
|
||||
header svg text:first-child {
|
||||
font-size: 2rem;
|
||||
font-variant-caps: small-caps;
|
||||
font-weight: bold; }
|
||||
|
||||
header svg text:last-child { font-size: .88rem; }
|
||||
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
#logo .logo { font-size: 2.082rem; } }
|
||||
header svg text:first-child { font-size: 2.082rem; } }
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
#logo .logo { font-size: 2rem; } }
|
||||
|
||||
#logo .under { font-size: .88rem; }
|
||||
header svg text:first-child { font-size: 2rem; } }
|
||||
|
||||
nav { margin-top: .5rem; }
|
||||
|
||||
|
@ -105,6 +104,60 @@ nav h1 {
|
|||
|
||||
section { margin-top: 1rem; }
|
||||
|
||||
input[name="filter"] {
|
||||
background-color: var(--background-color);
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--primary-color);
|
||||
color: var(--text-color);
|
||||
font: inherit;
|
||||
width: 100%; }
|
||||
|
||||
table {
|
||||
overflow-y: scroll;
|
||||
width: 100%; }
|
||||
|
||||
tr { vertical-align: top; }
|
||||
|
||||
tr:hover,
|
||||
tr:focus-within {
|
||||
background-color: var(--primary-color);
|
||||
color: white; }
|
||||
|
||||
tr:hover a,
|
||||
tr:focus-within 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; }
|
||||
|
||||
thead tr th.clickable { cursor: pointer; }
|
||||
|
||||
thead tr th.clickable:hover { color: var(--secondary-color); }
|
||||
|
||||
thead tr th.clickable:not(.sort-up):not(.sort-down)::after { content: '⇅'; }
|
||||
|
||||
thead tr th.clickable.sort-up::after { content: '↑'; }
|
||||
|
||||
thead tr th.clickable.sort-down::after { content: '↓'; }
|
||||
|
||||
#overlay {
|
||||
align-items: center;
|
||||
background-color: var(--overlay-background-color);
|
||||
|
@ -152,51 +205,13 @@ section { margin-top: 1rem; }
|
|||
background-color: var(--background-color);
|
||||
color: var(--primary-color); }
|
||||
|
||||
input[name="filter"] {
|
||||
background-color: var(--background-color);
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--primary-color);
|
||||
color: var(--text-color);
|
||||
font: inherit;
|
||||
width: 100%; }
|
||||
#error {
|
||||
font-size: 3.5rem;
|
||||
line-height: 5rem;
|
||||
text-align: center;
|
||||
margin: 6rem 0; }
|
||||
|
||||
table { overflow-y: scroll; width: 100%; }
|
||||
|
||||
tr { vertical-align: top; }
|
||||
|
||||
tr:hover,
|
||||
tr:focus-within { background-color: var(--primary-color); color: white; }
|
||||
|
||||
tr:hover a,
|
||||
tr:focus-within 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; }
|
||||
|
||||
thead tr th.clickable { cursor: pointer; }
|
||||
|
||||
thead tr th.clickable:hover { color: var(--secondary-color); }
|
||||
|
||||
thead tr th.clickable:not(.sort-up):not(.sort-down)::after { content: '⇅'; }
|
||||
|
||||
thead tr th.clickable.sort-up::after { content: '↑'; }
|
||||
|
||||
thead tr th.clickable.sort-down::after { content: '↓'; }
|
||||
#error h1 { font-size: 8rem; }
|
||||
|
||||
footer {
|
||||
font-size: .8rem;
|
||||
|
@ -206,7 +221,7 @@ footer {
|
|||
@media screen and (max-width: 640px) {
|
||||
header { display: block; }
|
||||
|
||||
#logo {
|
||||
header svg {
|
||||
margin: 0 auto;
|
||||
width: 100%; }
|
||||
|
||||
|
|
|
@ -13,13 +13,11 @@ html(lang='en')
|
|||
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
|
||||
svg(viewBox='0 -25 216 40')
|
||||
text Arav's dwelling
|
||||
text(y='11') Welcome to my sacred place, wanderer
|
||||
nav
|
||||
block nav
|
||||
block content
|
||||
footer
|
||||
a(href='/rss.xml' title="Stay up to date on what's going on.") RSS feed
|
||||
br
|
||||
| 2017—2023 Arav <#[a(href='mailto:me@arav.su') me@arav.su]> #[a(href='/privacy') Privacy statements]
|
||||
| 2017—2023 Alexander "Arav" Andreev <#[a(href='mailto:me@arav.su') me@arav.su]> #[a(href='/privacy') Privacy statements]
|
||||
|
|
|
@ -3,9 +3,6 @@ extends base.jade
|
|||
block meta_description
|
||||
meta(name='description' content=http.StatusText(code))
|
||||
|
||||
block append head
|
||||
link(href='/assets/css/error.css' rel='stylesheet')
|
||||
|
||||
block nav
|
||||
a(href='/') Back to index page
|
||||
h1 #{http.StatusText(code)}
|
||||
|
|
|
@ -5,10 +5,10 @@ block nav
|
|||
h1 Files
|
||||
|
||||
block content
|
||||
:go:func Index(title, mainSite, currentPath string, stats *files.DirStats, items *[]files.DirEntry, r *http.Request)
|
||||
:go:func Index(title, mainSite, currentPath string, stats *files.DirStat, items *[]files.DirEntry, r *http.Request)
|
||||
:go:import "dwelling-files/pkg/files"
|
||||
:go:import "dwelling-files/pkg/utils"
|
||||
section#files
|
||||
section
|
||||
span!= currentPath
|
||||
p Files: #{stats.Files} (#{stats.FilesSize}); Directories: #{stats.Directories}.
|
||||
input.hidden(type="text", name="filter" placeholder="Type in to filter this directory (case insensitive)")
|
||||
|
@ -28,7 +28,7 @@ block content
|
|||
td= item.Size
|
||||
section
|
||||
span!= currentPath
|
||||
section#usage
|
||||
section
|
||||
p On a page use up and down arrow keys to navigate through list. Use home and end keys to go to the start and end of a list. Use Ctrl+Backspace to return to a parent directory.
|
||||
p In an overlay use a mouse wheel to change a scale of a video or a picture. Use left and right arrow keys to go through media. Use space key to toggle pause. Use escape key to close an overlay, or click outside a media. An audio volume is being kept across site using LocalStorage API.
|
||||
div#overlay
|
||||
|
|
Loading…
Reference in New Issue