Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .air.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
root = "."
tmp_dir = "tmp"
[build]
cmd = "go build -o ./tmp/stalkarr ./cmd/server"
bin = "./tmp/stalkarr"
full_bin = "DATA_DIR=./config ./tmp/stalkarr"
cmd = "go build -o ./tmp/sleeparr ./cmd/server"
bin = "./tmp/sleeparr"
full_bin = "DATA_DIR=./config ./tmp/sleeparr"
delay = 1000
exclude_dir = ["frontend", "tmp", "data", "internal/static/dist"]
include_ext = ["go"]
Expand Down
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -----------------------------------------------
# stalkarr — environment configuration
# sleeparr — environment configuration
# -----------------------------------------------

# REQUIRED — generate with: openssl rand -hex 32
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Release

on:
push:
branches: [main]
branches: [main, "feat/**", "chore/**", "fix/**"]
tags:
- "v*"

Expand Down Expand Up @@ -34,6 +34,7 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch,enable=${{ !startsWith(github.ref, 'refs/heads/main') }}
type=raw,value=dev,enable={{is_default_branch}}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build output
/stalkarr
/sleeparr
frontend/dist
internal/static/dist/*
!internal/static/dist/.gitkeep
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ COPY --from=frontend-builder /app/frontend/dist ./internal/static/dist

ARG VERSION=dev
RUN CGO_ENABLED=0 GOOS=linux go build \
-ldflags="-s -w -X stalkarr/internal/version.Version=${VERSION}" \
-o stalkarr ./cmd/server
-ldflags="-s -w -X sleeparr/internal/version.Version=${VERSION}" \
-o sleeparr ./cmd/server

# ---- Stage 3: Final image ----
FROM alpine:3.19

RUN apk add --no-cache su-exec tzdata

WORKDIR /app
COPY --from=go-builder /app/stalkarr .
COPY --from=go-builder /app/sleeparr .

COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# STALKARR
# SLEEPARR

> **Personal project in BETA!** I built this for my own homelab using the tools I use daily: [Zed](https://zed.dev), [Claude](https://claude.ai), and [OpenCode](https://opencode.ai). AI is part of my regular workflow the same way Stack Overflow and docs always have been. If you spot any issues, chuck in a ticket and I'll get to it.

Expand All @@ -7,8 +7,8 @@ A self-hosted dashboard for searching missing media across your arr stack.
> Currently supports **Sonarr**. Radarr support coming soon.

<p align="center">
<img src="docs/desktop.png" alt="stalkarr desktop" width="600"/>
<img src="docs/mobile.png" alt="stalkarr mobile" width="200"/>
<img src="docs/desktop.png" alt="sleeparr desktop" width="600"/>
<img src="docs/mobile.png" alt="sleeparr mobile" width="200"/>
</p>

## Quick start
Expand All @@ -27,9 +27,9 @@ docker compose up -d
## docker-compose.yml
```yaml
services:
stalkarr:
image: ghcr.io/codevski/stalkarr:latest
container_name: stalkarr
sleeparr:
image: ghcr.io/codevski/sleeparr:latest
container_name: sleeparr
restart: unless-stopped
ports:
- "${PORT:-8080}:8080"
Expand Down Expand Up @@ -82,7 +82,7 @@ air
cd frontend && bun run dev
```

See `bruno/stalkarr/` for the API collection.
See `bruno/sleeparr/` for the API collection.

## License

Expand Down
File renamed without changes.
6 changes: 3 additions & 3 deletions bruno/stalkarr/README.md → bruno/sleeparr/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Stalkarr — Bruno Collection
# Sleeparr — Bruno Collection

API tests for the Stalkarr backend. Uses [Bruno](https://www.usebruno.com/) a git-friendly API client.
API tests for the Sleeparr backend. Uses [Bruno](https://www.usebruno.com/) a git-friendly API client.

## Setup

1. Install Bruno: https://www.usebruno.com/downloads
2. Open Bruno → **Open Collection** → select this `bruno/stalkarr` folder
2. Open Bruno → **Open Collection** → select this `bruno/sleeparr` folder
3. Select the **Local** environment (top right dropdown)

## First run order
Expand Down
File renamed without changes.
File renamed without changes.
9 changes: 3 additions & 6 deletions bruno/stalkarr/bruno.json → bruno/sleeparr/bruno.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
{
"version": "1",
"name": "Stalkarr",
"name": "Sleeparr",
"type": "collection",
"ignore": [
"node_modules",
".git"
],
"ignore": ["node_modules", ".git"],
"size": 0.0018472671508789062,
"filesCount": 7,
"presets": {
"requestType": "http",
"requestUrl": ""
}
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ auth:bearer {
body:json {
{
"sonarr": {
"url": "http://localhost:8989",
"api_key": "your-sonarr-api-key-here"
"url": "http://192.168.1.6:8989",
"api_key": ""
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions bruno/sleeparr/sonarr/trigger-run.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
meta {
name: Trigger Agent
type: http
seq: 2
}

post {
url: {{base_url}}/api/sonarr/run
body: none
auth: bearer
}

auth:bearer {
token: {{token}}
}

docs {
Triggers a agent run. Currently a stub returns {"status": "running"}.
}
19 changes: 0 additions & 19 deletions bruno/stalkarr/sonarr/trigger-hunt.bru

This file was deleted.

22 changes: 11 additions & 11 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"net/http"
"os"
"os/signal"
"stalkarr/internal/api"
"stalkarr/internal/config"
"stalkarr/internal/jobs"
"sleeparr/internal/api"
"sleeparr/internal/config"
"sleeparr/internal/jobs"
"syscall"
"time"

Expand All @@ -29,12 +29,12 @@ func main() {
log.Fatalf("failed to load config: %v", err)
}

stalkerCtx, stalkerCancel := context.WithCancel(context.Background())
defer stalkerCancel()
stalker := jobs.NewStalkerJob(config.Get)
go stalker.Start(stalkerCtx)
agentCtx, agentCancel := context.WithCancel(context.Background())
defer agentCancel()
agent := jobs.NewAgentJob(config.Get)
go agent.Start(agentCtx)

r := api.NewRouter(stalker)
r := api.NewRouter(agent)
r.SetTrustedProxies(nil)

port := os.Getenv("PORT")
Expand All @@ -48,7 +48,7 @@ func main() {
}

go func() {
log.Printf("Stalkarr running on :%s (data: %s)", port, dataDir)
log.Printf("Sleeparr running on :%s (data: %s)", port, dataDir)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("server error: %v", err)
}
Expand All @@ -62,9 +62,9 @@ func main() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

stalkerCancel()
agentCancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("forced shutdown: %v", err)
}
log.Println("Stalkarr stopped")
log.Println("Sleeparr stopped")
}
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
services:
stalkarr:
image: ghcr.io/codevski/stalkarr:latest
container_name: stalkarr
sleeparr:
image: ghcr.io/codevski/sleeparr:latest
container_name: sleeparr
restart: unless-stopped
ports:
- "${PORT:-8080}:8080"
Expand Down
16 changes: 8 additions & 8 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ PGID=${PGID:-1000}

echo "
─────────────────────────────────────
stalkarr
sleeparr
─────────────────────────────────────
User UID: ${PUID}
User GID: ${PGID}
─────────────────────────────────────
"

if ! getent group stalkarr > /dev/null 2>&1; then
addgroup -g "$PGID" stalkarr
if ! getent group sleeparr > /dev/null 2>&1; then
addgroup -g "$PGID" sleeparr
fi

if ! getent passwd stalkarr > /dev/null 2>&1; then
adduser -D -u "$PUID" -G stalkarr stalkarr
if ! getent passwd sleeparr > /dev/null 2>&1; then
adduser -D -u "$PUID" -G sleeparr sleeparr
fi

mkdir -p /config
chown -R stalkarr:stalkarr /config
chown -R stalkarr:stalkarr /app
chown -R sleeparr:sleeparr /config
chown -R sleeparr:sleeparr /app

exec su-exec stalkarr:stalkarr /app/stalkarr
exec su-exec sleeparr:sleeparr /app/sleeparr
2 changes: 1 addition & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>stalkarr</title>
<title>sleeparr</title>
</head>
<body>
<div id="root"></div>
Expand Down
4 changes: 2 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "stalkarr",
"name": "sleeparr",
"private": true,
"version": "0.0.1",
"version": "0.0.2",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ExternalLink } from "lucide-react";
import api from "@/lib/api";
import type { VersionInfo } from "@/types";

const RELEASES_URL = "https://github.com/codevski/stalkarr/releases/latest";
const RELEASES_URL = "https://github.com/codevski/sleeparr/releases/latest";

export default function Footer() {
const [version, setVersion] = useState<VersionInfo | null>(null);
Expand All @@ -18,7 +18,7 @@ export default function Footer() {
return (
<footer className="border-t border-border/50 py-3 mt-auto">
<div className="max-w-6xl mx-auto px-4 flex items-center justify-between text-xs text-muted-foreground">
<span>stalkarr</span>
<span>sleeparr</span>
<div className="flex items-center gap-3">
{version && <span className="font-mono">{version.current}</span>}
{version?.hasUpdate && (
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function Layout() {
<div className="flex items-center gap-2 mr-2">
<Radio className="w-4 h-4 text-primary" />
<span className="font-semibold tracking-tight text-sm">
stalkarr
sleeparr
</span>
</div>

Expand Down
16 changes: 8 additions & 8 deletions frontend/src/pages/DashboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import type { InstanceSummary } from "@/types";
export default function DashboardPage() {
const [sonarr, setSonarr] = useState<InstanceSummary[]>([]);
const [loading, setLoading] = useState(true);
const [stalksToday, setStalksToday] = useState(0);
const [runsToday, setRunsToday] = useState(0);

useEffect(() => {
api
.get("/api/dashboard")
.then((res) => {
setSonarr(res.data.sonarr);
setStalksToday(res.data.stalksToday);
setRunsToday(res.data.runsToday);
})
.finally(() => setLoading(false));
}, [setStalksToday]);
}, [setRunsToday]);

const totalMissing = sonarr.reduce(
(acc, s) => acc + (s.missingCount ?? 0),
Expand All @@ -44,8 +44,8 @@ export default function DashboardPage() {
},
{ label: "Missing Movies", value: "—" },
{
label: "Stalks Today",
value: loading ? "—" : stalksToday.toString(),
label: "Runs Today",
value: loading ? "—" : runsToday.toString(),
},
{ label: "Found Today", value: "0" },
].map(({ label, value }) => (
Expand Down Expand Up @@ -117,11 +117,11 @@ export default function DashboardPage() {
</div>
<div className="flex items-center justify-between text-sm mt-2">
<span className="text-muted-foreground flex items-center gap-1.5">
<Clock className="w-3 h-3" /> Last stalk
<Clock className="w-3 h-3" /> Last run
</span>
<span className="text-muted-foreground">
{inst.lastStalk
? new Date(inst.lastStalk).toLocaleTimeString([], {
{inst.lastRun
? new Date(inst.lastRun).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
})
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function LoginPage() {
<div className="flex justify-center mb-2">
<Radio className="w-8 h-8 text-primary" />
</div>
<CardTitle className="text-2xl">stalkarr</CardTitle>
<CardTitle className="text-2xl">sleeparr</CardTitle>
<CardDescription>Sign in to your instance</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4">
Expand Down
Loading
Loading