krz/skunky-art
Alternative privacy frontend for DeviantArt.
clone: git clone https://gitbay.org/krz/skunky-art.git
2a420dbcd2ecc545737f312e1ca5f53f18c8eac6
unsigned
author: Christian Cleberg <hello@cleberg.net> · 2026-08-08T20:32:25Z
.github/workflows/release.yml | 12 ++++++------ Dockerfile | 3 ++- app/cache_test.go | 2 +- app/wrapper.go | 6 +++--- static/html/about.htm | 2 +- static/html/daily.htm | 2 +- static/html/deviantion.htm | 6 +++--- static/html/gruser.htm | 10 +++++----- static/html/head.htm | 2 +- static/html/header.htm | 4 ++-- static/html/index.htm | 10 +++++----- static/html/search.htm | 2 +- 12 files changed, 31 insertions(+), 30 deletions(-) @@ -20,15 +20,15 @@ jobs: attestations: write steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 # The Dockerfile cross-compiles with Go's GOOS/GOARCH from $BUILDPLATFORM, # so no QEMU emulation is needed for the arm64 image. - name: Set up Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 - name: Log in to ${{ env.REGISTRY }} - uses: docker/login-action@v4 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -36,7 +36,7 @@ jobs: - name: Derive tags and labels id: meta - uses: docker/metadata-action@v6 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # A semver tag v1.3.4 publishes 1.3.4, 1.3, 1 and latest. @@ -53,7 +53,7 @@ jobs: - name: Build and push id: build - uses: docker/build-push-action@v7 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 with: context: . platforms: linux/amd64,linux/arm64 @@ -68,7 +68,7 @@ jobs: cache-to: type=gha,mode=max - name: Attest build provenance - uses: actions/attest-build-provenance@v4 + uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4 with: subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} subject-digest: ${{ steps.build.outputs.digest }} @@ -8,7 +8,8 @@ ARG VERSION=dev WORKDIR /build COPY . . -RUN CGO_ENABLED=0 GOARCH=${TARGETARCH} GOOS=${TARGETOS} go build -ldflags "-s -w -extldflags '-static' -X main.version=${VERSION}" && \ +RUN CGO_ENABLED=0 GOARCH="${TARGETARCH}" GOOS="${TARGETOS}" \ + go build -ldflags "-s -w -extldflags '-static' -X main.version=${VERSION}" && \ echo "skunkyart:x:10000:10000:SkunkyArt user:/:/sbin/nologin" > /etc/minimal-passwd && \ echo "skunkyart:x:10000:" > /etc/minimal-group @@ -278,7 +278,7 @@ func TestAgeMemCacheEvicts(t *testing.T) { if got := memGet(cold); got != nil { t.Errorf("cold entry survived aging: got %q, want nil", got) } - if got := memGet(hot); got == nil { + if memGet(hot) == nil { t.Error("hot entry was evicted after a hit, want it kept") } } @@ -89,7 +89,7 @@ func (s skunkyart) GRUser() { folderid, _ := strconv.Atoi(s.Args.Get("folder")) - if a := s.Args.Get("all"); a == "true" { + if s.Args.Get("all") == "true" { all = true } @@ -115,7 +115,7 @@ func (s skunkyart) GRUser() { }) } else { for _, x := range content.Content.Gruser.Page.Modules { - if l := len(x.ModuleData.Folders.Results); l != 0 { + if len(x.ModuleData.Folders.Results) != 0 { var folders strings.Builder folders.WriteString(`<h1 id="folders"><a href="#folder">#</a> Folders</h1><div class="folders"><br>`) for _, x := range x.ModuleData.Folders.Results { @@ -309,7 +309,7 @@ func (s skunkyart) Search() { } } - if l := len(usernames); l != 0 { + if len(usernames) != 0 { ss.List += `<div class="content plates">` for x := range len(usernames) { ss.List += BuildUserPlate(s.Host, usernames[x]) @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html> +<html lang="en"> {{template "head" .}} <main> {{template "header" .}} @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html> +<html lang="en"> {{template "head" . }} <main> {{template "header" . }} @@ -1,10 +1,10 @@ <!DOCTYPE html> -<html> +<html lang="en"> {{template "head" . }} <main> {{template "header" . }} <figure> - <img src="{{.BasePath}}media/emojitar/{{.Templates.Deviation.Post.Deviation.Author.Username}}?type=a" width="30px"> + <img src="{{.BasePath}}media/emojitar/{{.Templates.Deviation.Post.Deviation.Author.Username}}?type=a" width="30px" alt="{{.Templates.Deviation.Post.Deviation.Author.Username}} avatar"> <span><strong><a href="{{.BasePath}}group_user?type=about&q={{.Templates.Deviation.Post.Deviation.Author.Username}}">{{.Templates.Deviation.Post.Deviation.Author.Username}}</a></strong> — {{if (.Templates.Deviation.Post.Deviation.DD)}} <span class="dd" title="Daily Deviation!"><b>{{.Templates.Deviation.Post.Deviation.Title}}</b></span> {{else}}{{.Templates.Deviation.Post.Deviation.Title}}{{end}} @@ -13,7 +13,7 @@ </span> <br> {{if (ne .Templates.Deviation.Post.IMG "")}} - <a href="{{.Templates.Deviation.Post.IMG}}" title="open/download image"><img src="{{.Templates.Deviation.Post.IMG}}" width="50%"></a> + <a href="{{.Templates.Deviation.Post.IMG}}" title="open/download image"><img src="{{.Templates.Deviation.Post.IMG}}" width="50%" alt="{{.Templates.Deviation.Post.Deviation.Title}}"></a> <br> {{end}} {{if (ne .Templates.Deviation.Tags "")}} @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html> +<html lang="en"> {{template "head" . }} <main> <header> @@ -17,9 +17,9 @@ | <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type=gallery&atom=true">RSS</a> </h1> <form method="get" action="{{.BasePath}}search"> - <input type="gallery" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false"> + <input type="text" name="q" aria-label="Search query" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false"> <input type="hidden" name="usr" value="{{.Templates.GroupUser.GR.Owner.Username}}"> - <select name="type"> + <select name="type" aria-label="Search type"> <option value="gallery">Gallery</option> <option value="folders">Folders</option> <option value="all">All</option> @@ -31,11 +31,11 @@ </header> {{if eq .Type 'a'}} {{if and (and (ne .Templates.About.Nsfw true) (ne .Templates.GroupUser.About.BGMeta.NSFW true)) (ne .Templates.GroupUser.About.BG "")}} - <a href="{{.Templates.GroupUser.About.BGMeta.Url}}" class="ubg"><img title="{{if ne .Templates.GroupUser.GR.Owner.Username .Templates.GroupUser.About.BGMeta.Author.Username}} + <a href="{{.Templates.GroupUser.About.BGMeta.Url}}" class="ubg"><img alt="Profile background" title="{{if ne .Templates.GroupUser.GR.Owner.Username .Templates.GroupUser.About.BGMeta.Author.Username}} {{.Templates.GroupUser.About.BGMeta.Author.Username}} - {{end}}{{.Templates.GroupUser.About.BGMeta.Title}}" src="{{.Templates.GroupUser.About.BG}}"></a> {{end}} - <img src="{{.BasePath}}media/emojitar/{{.Templates.GroupUser.GR.Owner.Username}}?type=a" width="30px" height="30px"> <b>{{.Templates.GroupUser.GR.Owner.Username}}</b> + <img src="{{.BasePath}}media/emojitar/{{.Templates.GroupUser.GR.Owner.Username}}?type=a" width="30px" height="30px" alt="{{.Templates.GroupUser.GR.Owner.Username}} avatar"> <b>{{.Templates.GroupUser.GR.Owner.Username}}</b> {{if (eq .Templates.GroupUser.About.A.Gender "male")}} ♂️ {{end}} @@ -21,6 +21,6 @@ <meta name="referrer" content="no-referrer" /> <link rel="stylesheet" href="{{.BasePath}}stylesheet"> <link rel="icon" type="image/x-icon" href="{{.BasePath}}favicon.ico"> - <meta name="viewport" content="width=device-width, height=device-height, initial-scale=0.4, user-scalable=no"/> + <meta name="viewport" content="width=device-width, height=device-height, initial-scale=0.4"/> </head> {{end}} \ No newline at end of file @@ -2,8 +2,8 @@ <header> <h1><a href="">HOME</a> | <a href="dd">DD</a> {{if eq .Endpoint "dd"}}| <a href="{{.Endpoint}}?atom=true">RSS</a>{{end}}</h1> <form method="get" action="search"> - <input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false" value="{{.QueryRaw}}"> - <select name="type"> + <input type="text" name="q" aria-label="Search query" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false" value="{{.QueryRaw}}"> + <select name="type" aria-label="Search type"> <option value="all">All</option> <option value="tag">Tag</option> <option value="r">Groups</option> @@ -1,10 +1,10 @@ <!DOCTYPE html> -<html> +<html lang="en"> <head> <title>SkunkyArt</title> <link rel="stylesheet" href="{{.}}stylesheet"/> <link rel="icon" type="image/x-icon" href="{{.}}favicon.ico"> - <meta name="viewport" content="width=device-width, height=device-height, initial-scale=0.4, user-scalable=no; user-scalable=0"/> + <meta name="viewport" content="width=device-width, height=device-height, initial-scale=0.4"/> <style> main { @@ -70,12 +70,12 @@ </style> </head> <main> - <img src="{{.}}favicon.ico" title="SkunkyArt logo" draggable="false"> + <img src="{{.}}favicon.ico" title="SkunkyArt logo" alt="SkunkyArt logo" draggable="false"> <div> <h1><a href="{{.}}dd">Daily Deviations</a> | <a href="{{.}}about">About</a></h1> <form method="get" action="{{.}}search"> - <input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false"> - <select name="type"> + <input type="text" name="q" aria-label="Search query" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false"> + <select name="type" aria-label="Search type"> <option value="all">All</option> <option value="tag">Tag</option> <option value="r">Groups</option> @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html> +<html lang="en"> {{template "head" . }} <main> {{template "header" . }}