Commit 9db3cae4a5
Verified · cmc ci/build: success ci/lint: success ci/test: success
Layout: unified · split
README.org +43 −2
| @@ -7,9 +7,29 @@ this fork keeps it maintained. | |||
| 7 | 7 | ||
| 8 | * what | 8 | * what |
| 9 | skunkyart. alternative frontend for deviantart. works with no javascript. | 9 | skunkyart. alternative frontend for deviantart. works with no javascript. |
| 10 | one instance, one config file, no database. | ||
| 10 | 11 | ||
| 11 | instances: [[file:INSTANCES.md][INSTANCES.md]] | 12 | instances: [[file:INSTANCES.md][INSTANCES.md]] |
| 12 | 13 | ||
| 14 | pages: | ||
| 15 | |||
| 16 | - ~/~ search box, links to daily deviations and about | ||
| 17 | - ~/dd~ daily deviations; ~?atom=true~ for the feed | ||
| 18 | - ~/search?q=<q>&type=all|tag|r~ search art, tags, or groups | ||
| 19 | - ~/post/<author>/<name-id>~ one deviation, with a link to its comments | ||
| 20 | - ~/group_user?q=<name>&type=about|gallery|favourites~ a user or group; | ||
| 21 | ~&atom=true~ on a gallery for its feed | ||
| 22 | - ~/api/...~ json, documented in [[file:API.md][API.md]] | ||
| 23 | |||
| 24 | [[file:REDIRECTS.md][REDIRECTS.md]] maps deviantart.com urls onto these, for browser redirector | ||
| 25 | extensions such as libredirect. | ||
| 26 | |||
| 27 | deviantart blocks egress ips that ask too often, so the instance keeps its | ||
| 28 | upstream traffic down: api responses are cached in memory and coalesced, media | ||
| 29 | and avatars are cached on disk, comments load on request, pages carry | ||
| 30 | cache-control headers, crawlers get a robots.txt, and each client has a | ||
| 31 | request budget. all of it is on by default and tunable in [[file:SETUP.md][SETUP.md]]. | ||
| 32 | |||
| 13 | * build | 33 | * build |
| 14 | build with the embed tag to embed presets in the binary. skip the tag if you'll | 34 | build with the embed tag to embed presets in the binary. skip the tag if you'll |
| 15 | modify templates. add ~-ldflags "-w -s"~ (~gccgo: gccgoflags~) to shrink the output: | 35 | modify templates. add ~-ldflags "-w -s"~ (~gccgo: gccgoflags~) to shrink the output: |
| @@ -21,6 +41,19 @@ go build -tags embed -ldflags "-w -s" | |||
| 21 | that build reports its version as dev. stamp one in with ~-X | 41 | that build reports its version as dev. stamp one in with ~-X |
| 22 | main.version=<version>~, as the release workflow does from the git tag. | 42 | main.version=<version>~, as the release workflow does from the git tag. |
| 23 | 43 | ||
| 44 | * run | ||
| 45 | without docker: put the binary (and ~static/~, unless built with the embed | ||
| 46 | tag) in a directory with a ~config.json~, then | ||
| 47 | |||
| 48 | #+begin_src sh | ||
| 49 | ./skunkyart -c config.json | ||
| 50 | #+end_src | ||
| 51 | |||
| 52 | ~config.json~ is optional; without it the built-in defaults listen on | ||
| 53 | 127.0.0.1:3003 with the caches on. service files for systemd and openrc are in | ||
| 54 | [[file:services/][services/]]. put a reverse proxy with tls in front; SETUP.md has the nginx | ||
| 55 | stanza. | ||
| 56 | |||
| 24 | * docker | 57 | * docker |
| 25 | multi-arch images (~linux/amd64~, ~linux/arm64~) publish to ghcr on every release | 58 | multi-arch images (~linux/amd64~, ~linux/arm64~) publish to ghcr on every release |
| 26 | tag: | 59 | tag: |
| @@ -37,6 +70,14 @@ reproducible upgrades. [[file:compose.example.yaml][compose.example.yaml]] uses | |||
| 37 | sample config in [[file:config.example.json][config.example.json]]. custom config with ~--config~. directive | 70 | sample config in [[file:config.example.json][config.example.json]]. custom config with ~--config~. directive |
| 38 | details in [[file:SETUP.md][SETUP.md]]. | 71 | details in [[file:SETUP.md][SETUP.md]]. |
| 39 | 72 | ||
| 73 | * develop | ||
| 74 | #+begin_src sh | ||
| 75 | go test ./... -race | ||
| 76 | go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.13.2 run ./... | ||
| 77 | #+end_src | ||
| 78 | |||
| 79 | ci runs both on every push. the roadmap is [[file:ROADMAP.md][ROADMAP.md]]. | ||
| 80 | |||
| 40 | * instances | 81 | * instances |
| 41 | add yours by pr to [[file:instances.json][instances.json]] and [[file:INSTANCES.md][INSTANCES.md]] (or use ~--add-instance~ to | 82 | add yours by merge request to [[file:instances.json][instances.json]] and [[file:INSTANCES.md][INSTANCES.md]] (or use |
| 42 | write both), or open an issue. | 83 | ~--add-instance~ to write both), or open an issue. |
services/skunkyart.example.service +31 −4
| @@ -1,11 +1,38 @@ | |||
| 1 | # Note: i didn't use systemd, so it can be not works :) | 1 | # systemd unit for SkunkyArt. Install the binary and its static/ directory |
| 2 | # (or a binary built with -tags embed) under /opt/skunkyart, put config.json | ||
| 3 | # beside it, then: | ||
| 4 | # | ||
| 5 | # cp services/skunkyart.example.service /etc/systemd/system/skunkyart.service | ||
| 6 | # systemctl daemon-reload | ||
| 7 | # systemctl enable --now skunkyart | ||
| 8 | # | ||
| 9 | # DynamicUser gives the service a throwaway account with no home and no | ||
| 10 | # shell; StateDirectory is the one writable place it gets, mounted at | ||
| 11 | # /var/lib/skunkyart, which is where the media cache goes. | ||
| 2 | 12 | ||
| 3 | [Unit] | 13 | [Unit] |
| 4 | Description=Privacy-oriented frontend for DeviantArt | 14 | Description=SkunkyArt, an alternative frontend for DeviantArt |
| 15 | After=network-online.target | ||
| 16 | Wants=network-online.target | ||
| 5 | 17 | ||
| 6 | [Service] | 18 | [Service] |
| 7 | Directory=<path-to-dir-with-skunkyart> | 19 | WorkingDirectory=/opt/skunkyart |
| 8 | ExecStart=<path-to-dir-skunkyart> | 20 | ExecStart=/opt/skunkyart/skunkyart -c /opt/skunkyart/config.json |
| 21 | Restart=on-failure | ||
| 22 | RestartSec=5s | ||
| 23 | |||
| 24 | DynamicUser=yes | ||
| 25 | StateDirectory=skunkyart | ||
| 26 | # Point "cache": {"path": "/var/lib/skunkyart"} at the state directory. | ||
| 27 | ProtectSystem=strict | ||
| 28 | ProtectHome=yes | ||
| 29 | PrivateTmp=yes | ||
| 30 | NoNewPrivileges=yes | ||
| 31 | PrivateDevices=yes | ||
| 32 | ProtectKernelTunables=yes | ||
| 33 | ProtectControlGroups=yes | ||
| 34 | RestrictAddressFamilies=AF_INET AF_INET6 | ||
| 35 | LockPersonality=yes | ||
| 9 | 36 | ||
| 10 | [Install] | 37 | [Install] |
| 11 | WantedBy=multi-user.target | 38 | WantedBy=multi-user.target |