Add StartOS 0.4.0 packaging
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# Deploy on StartOS 0.4.0
|
||||
|
||||
This file documents how to build and deploy YouTube Summarizer on StartOS 0.4.0.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker with `buildx` support (for ARM64 cross-compilation)
|
||||
- `start-sdk` CLI tool installed ([docs.start9.com](https://docs.start9.com))
|
||||
- Git (required by `start-sdk pack`)
|
||||
|
||||
## 0) One-time Git setup
|
||||
|
||||
`start-sdk pack` requires a Git repository in the project folder.
|
||||
|
||||
```bash
|
||||
cd /Users/macpro/Projects/youtube-summarizer
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial commit for Start9 packaging"
|
||||
```
|
||||
|
||||
## 1) Build package
|
||||
|
||||
```bash
|
||||
cd /Users/macpro/Projects/youtube-summarizer
|
||||
|
||||
# For x86_64 servers (Intel NUC, mini PC, custom build) — the default:
|
||||
make -C start9/0.4 package
|
||||
|
||||
# For ARM64 servers (Raspberry Pi, Start9 original hardware):
|
||||
make -C start9/0.4 package PLATFORM=linux/arm64
|
||||
```
|
||||
|
||||
This creates:
|
||||
- `start9/0.4/image.tar` (Docker image for your server's architecture)
|
||||
- `start9/0.4/youtube-summarizer.s9pk` (installable package)
|
||||
|
||||
## 2) Upload to StartOS
|
||||
|
||||
1. Open the StartOS web UI.
|
||||
2. Go to Services > Sideload Package.
|
||||
3. Upload `start9/0.4/youtube-summarizer.s9pk`.
|
||||
4. Install and start the service.
|
||||
|
||||
## 3) First run
|
||||
|
||||
1. Open the service UI.
|
||||
2. Go to Settings and enter your Gemini API key.
|
||||
3. (Recommended) Set up YouTube OAuth authentication.
|
||||
4. Run a manual StartOS backup.
|
||||
|
||||
## 4) Data persistence
|
||||
|
||||
All user data lives in `/data` on the StartOS service volume:
|
||||
- `/data/history/` — processed summaries, subscriptions, queue state
|
||||
- `/data/config/` — StartOS-managed configuration + processing config
|
||||
- `/data/cookies.txt` — YouTube cookie file (if uploaded)
|
||||
- `/data/bin/` — runtime-updated yt-dlp binary
|
||||
- `/data/ytdlp-cache/` — yt-dlp cache (OAuth tokens)
|
||||
- `/data/.env` — optional env overrides
|
||||
|
||||
This contract must be preserved across package versions.
|
||||
|
||||
Key config files:
|
||||
- `config/startos-config.json` — Gemini API key (set from UI)
|
||||
- `config/processing-config.json` — background queue delay + enabled state
|
||||
- `history/subscriptions.json` — subscriptions (with autoDownload flag)
|
||||
- `history/auto-queue.json` — processing queue state (survives restarts)
|
||||
|
||||
## 5) Updating the package
|
||||
|
||||
1. Make changes to the app or wrapper.
|
||||
2. Bump `version` in `start9/0.4/manifest.yaml`.
|
||||
3. Rebuild: `make -C start9/0.4 package`
|
||||
4. Sideload the new `.s9pk` — StartOS will upgrade in place.
|
||||
5. All data in `/data` is preserved across upgrades.
|
||||
@@ -0,0 +1,64 @@
|
||||
# ─────────────────────────────────────────────────────────
|
||||
# YouTube Summarizer — StartOS 0.4 Docker image
|
||||
#
|
||||
# Multi-stage build for ARM64 (Raspberry Pi / Start9 server)
|
||||
# Includes: Node.js 20, Python 3, yt-dlp, ffmpeg
|
||||
#
|
||||
# Uses Debian slim (not Alpine) because:
|
||||
# - yt-dlp's --impersonate chrome requires curl_cffi (compiled C extension)
|
||||
# - curl_cffi's prebuilt wheels target glibc, not musl
|
||||
# - Debian is more reliable for pip-installed packages with C deps on ARM64
|
||||
# ─────────────────────────────────────────────────────────
|
||||
|
||||
# ── Stage 1: Install Node.js dependencies ──────────────────
|
||||
FROM node:20-slim AS builder
|
||||
|
||||
WORKDIR /app/server
|
||||
COPY server/package.json server/package-lock.json* ./
|
||||
RUN npm ci --production --ignore-scripts 2>/dev/null || npm install --production --ignore-scripts
|
||||
|
||||
# ── Stage 2: Final runtime image ───────────────────────────
|
||||
FROM node:20-slim AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime dependencies:
|
||||
# - dumb-init: proper PID 1 signal handling in containers
|
||||
# - curl: health checks + yt-dlp binary downloads
|
||||
# - python3 + pip: yt-dlp installation and updates
|
||||
# - ffmpeg: audio extraction, splitting, and duration detection
|
||||
# - ca-certificates: HTTPS for YouTube/Gemini API calls
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
dumb-init \
|
||||
curl \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
ffmpeg \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip3 install --break-system-packages yt-dlp curl_cffi \
|
||||
&& yt-dlp --version
|
||||
|
||||
# Copy Node.js app from builder
|
||||
COPY --from=builder /app/server/node_modules ./server/node_modules/
|
||||
COPY server/package.json ./server/
|
||||
COPY server/index.js ./server/
|
||||
COPY public/ ./public/
|
||||
COPY assets/ ./assets/
|
||||
|
||||
# Copy StartOS scripts
|
||||
COPY start9/0.4/docker_entrypoint.sh /usr/local/bin/docker_entrypoint.sh
|
||||
COPY start9/0.4/healthcheck.sh /usr/local/bin/healthcheck.sh
|
||||
RUN chmod +x /usr/local/bin/docker_entrypoint.sh /usr/local/bin/healthcheck.sh
|
||||
|
||||
# Create persistent data mount point
|
||||
RUN mkdir -p /data
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
PORT=3001 \
|
||||
DATA_DIR=/data
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
ENTRYPOINT ["dumb-init", "--", "/usr/local/bin/docker_entrypoint.sh"]
|
||||
@@ -0,0 +1,10 @@
|
||||
Proprietary License
|
||||
|
||||
Copyright (c) 2026. All rights reserved.
|
||||
|
||||
This software and associated documentation files (the "Software") are
|
||||
proprietary. Unauthorized copying, modification, distribution, or use
|
||||
of this Software, via any medium, is strictly prohibited without prior
|
||||
written permission from the copyright holder.
|
||||
|
||||
The Software is provided "as is", without warranty of any kind.
|
||||
@@ -0,0 +1,26 @@
|
||||
PKG_ID := $(shell awk '/^id:/{print $$2; exit}' manifest.yaml)
|
||||
PKG_VERSION := $(shell awk '/^version:/{print $$2; exit}' manifest.yaml)
|
||||
REPO_ROOT := $(abspath ../..)
|
||||
WRAPPER_DIR := $(CURDIR)
|
||||
IMAGE_NAME := start9/$(PKG_ID)/main:$(PKG_VERSION)
|
||||
|
||||
# Default to x86_64; override with: make PLATFORM=linux/arm64 image
|
||||
PLATFORM ?= linux/amd64
|
||||
|
||||
.PHONY: image package verify clean
|
||||
|
||||
image:
|
||||
docker buildx build --platform=$(PLATFORM) \
|
||||
-f $(WRAPPER_DIR)/Dockerfile \
|
||||
-t $(IMAGE_NAME) \
|
||||
-o type=docker,dest=$(WRAPPER_DIR)/image.tar \
|
||||
$(REPO_ROOT)
|
||||
|
||||
package: image
|
||||
start-sdk pack
|
||||
|
||||
verify:
|
||||
start-sdk verify s9pk $(PKG_ID).s9pk
|
||||
|
||||
clean:
|
||||
rm -f $(WRAPPER_DIR)/image.tar $(WRAPPER_DIR)/$(PKG_ID).s9pk
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
DATA_DIR="/data"
|
||||
HISTORY_DIR="$DATA_DIR/history"
|
||||
CONFIG_DIR="$DATA_DIR/config"
|
||||
BIN_DIR="$DATA_DIR/bin"
|
||||
CACHE_DIR="$DATA_DIR/ytdlp-cache"
|
||||
|
||||
# Create directory structure on persistent volume
|
||||
mkdir -p "$HISTORY_DIR" "$CONFIG_DIR" "$BIN_DIR" "$CACHE_DIR"
|
||||
|
||||
# Ensure the non-root user owns the data volume
|
||||
# (on first boot the volume is root-owned; we need appuser to write)
|
||||
chown -R 1001:1001 "$DATA_DIR"
|
||||
|
||||
# Use persistent yt-dlp binary if available (runtime updates go here)
|
||||
if [ -x "$BIN_DIR/yt-dlp" ]; then
|
||||
export PATH="$BIN_DIR:$PATH"
|
||||
fi
|
||||
|
||||
# Point yt-dlp cache to persistent storage (stores OAuth tokens)
|
||||
export XDG_CACHE_HOME="$CACHE_DIR"
|
||||
|
||||
# Load Gemini API key from StartOS config if available
|
||||
if [ -f "$CONFIG_DIR/startos-config.json" ]; then
|
||||
GEMINI_KEY=$(python3 -c "import sys,json; print(json.load(open('$CONFIG_DIR/startos-config.json')).get('gemini_api_key',''))" 2>/dev/null || echo "")
|
||||
if [ -n "$GEMINI_KEY" ]; then
|
||||
export GEMINI_API_KEY="$GEMINI_KEY"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Also load from .env if it exists in data dir (user override)
|
||||
if [ -f "$DATA_DIR/.env" ]; then
|
||||
set -a
|
||||
. "$DATA_DIR/.env"
|
||||
set +a
|
||||
fi
|
||||
|
||||
export DATA_DIR="$DATA_DIR"
|
||||
export PORT="${PORT:-3001}"
|
||||
export HOSTNAME="0.0.0.0"
|
||||
|
||||
echo "Starting YouTube Summarizer..."
|
||||
echo " yt-dlp: $(yt-dlp --version 2>/dev/null || echo 'not found')"
|
||||
echo " ffmpeg: $(ffmpeg -version 2>/dev/null | head -1 || echo 'not found')"
|
||||
echo " Data: $DATA_DIR"
|
||||
|
||||
exec node /app/server/index.js
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
PORT="${PORT:-3001}"
|
||||
curl -fsS "http://127.0.0.1:${PORT}/api/health" >/dev/null
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,114 @@
|
||||
# YouTube Summarizer (StartOS)
|
||||
|
||||
## What This Package Does
|
||||
|
||||
YouTube Summarizer downloads audio from YouTube videos and podcast RSS feeds,
|
||||
transcribes them using Google Gemini AI, and produces structured topic summaries
|
||||
with timestamps. It supports channel subscriptions with automatic new episode
|
||||
detection and an organized history with folders.
|
||||
|
||||
## Requirements
|
||||
|
||||
You need a **Google Gemini API key** to use this service. A free tier is
|
||||
available:
|
||||
|
||||
1. Go to [aistudio.google.com/apikey](https://aistudio.google.com/apikey)
|
||||
2. Sign in with your Google account
|
||||
3. Click "Create API Key"
|
||||
4. Copy the key
|
||||
|
||||
## First Launch
|
||||
|
||||
1. Open the service web UI from StartOS.
|
||||
2. Click the **Settings** icon (gear) in the top-right.
|
||||
3. Paste your Gemini API key and save.
|
||||
4. You're ready to summarize! Paste a YouTube URL and click **Summarize**.
|
||||
|
||||
## YouTube Authentication (Recommended)
|
||||
|
||||
For reliable YouTube downloads, set up authentication using **one** of these
|
||||
methods:
|
||||
|
||||
### Option A: OAuth2 (Recommended — lasts indefinitely)
|
||||
|
||||
1. In the web UI, go to **Settings > YouTube Authentication**.
|
||||
2. Click **Start OAuth Setup**.
|
||||
3. You'll see a device code and a URL.
|
||||
4. On any device (phone, laptop), go to the URL and enter the code.
|
||||
5. Sign in with your Google account when prompted.
|
||||
6. The token is saved and will be used for all future downloads.
|
||||
|
||||
### Option B: Cookies File (expires every 3-5 days)
|
||||
|
||||
1. On your computer, export YouTube cookies from your browser using a
|
||||
cookies.txt browser extension.
|
||||
2. In the web UI, go to **Settings > YouTube Authentication**.
|
||||
3. Click **Upload cookies.txt** and select the file.
|
||||
4. Click **Test Cookies** to verify they work.
|
||||
|
||||
Note: YouTube cookies expire quickly (3-5 days). You will need to re-export
|
||||
and re-upload them regularly. OAuth2 is strongly recommended instead.
|
||||
|
||||
## Subscriptions
|
||||
|
||||
Add YouTube channels and podcast RSS feeds to automatically discover new
|
||||
episodes:
|
||||
|
||||
1. Click **Subscriptions** in the sidebar.
|
||||
2. Click **Add Subscription**.
|
||||
3. Paste a YouTube channel URL or podcast RSS feed URL.
|
||||
4. New episodes will appear in the **Queue** tab for your approval.
|
||||
5. Click **Approve** to send items to the background processor, or
|
||||
**Approve All** to queue everything at once.
|
||||
|
||||
### Auto-Download
|
||||
|
||||
For subscriptions you always want processed, enable **Auto-Download**:
|
||||
|
||||
1. In the **Subscriptions** list, toggle **Auto-Download** on for a subscription.
|
||||
2. New episodes from that subscription will be automatically approved and
|
||||
processed in the background — no manual approval needed.
|
||||
|
||||
### Background Processing Queue
|
||||
|
||||
Approved items are processed one at a time with a configurable delay between
|
||||
each (default: 5 minutes) to avoid triggering YouTube's rate limits.
|
||||
|
||||
- **Rush Mode**: If you want the next item processed immediately (no delay),
|
||||
use the Rush button in the Queue panel.
|
||||
- **Configure Delay**: Adjust the delay between items in Settings > Processing.
|
||||
Longer delays (5-10 minutes) are safer; shorter delays risk YouTube blocks.
|
||||
- **Pause/Resume**: You can pause background processing entirely and resume
|
||||
when ready.
|
||||
|
||||
## Updating yt-dlp
|
||||
|
||||
YouTube frequently changes its download systems. If downloads start failing:
|
||||
|
||||
1. Go to **StartOS > YouTube Summarizer > Actions**.
|
||||
2. Click **Update yt-dlp**.
|
||||
3. Wait for the update to complete.
|
||||
4. Try your download again.
|
||||
|
||||
The service also checks for yt-dlp updates automatically every 24 hours.
|
||||
|
||||
## Data & Backups
|
||||
|
||||
All your data (summaries, subscriptions, settings) is stored in the StartOS
|
||||
service volume and included in StartOS backups. Your Gemini API key is stored
|
||||
locally on this server and is never transmitted anywhere except to the Google
|
||||
Gemini API for processing.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"No API key provided"** — Enter your Gemini API key in Settings.
|
||||
|
||||
**"Download failed"** — YouTube may be rate-limiting. Wait a few minutes and
|
||||
try again. If persistent, run the "Update yt-dlp" action.
|
||||
|
||||
**"Sign in to confirm you're not a bot"** — Set up YouTube authentication
|
||||
(OAuth2 or cookies) in Settings.
|
||||
|
||||
**Summaries seem truncated** — Very long videos (3+ hours) are automatically
|
||||
split into chunks for transcription. If chunks are still truncated, try a
|
||||
different Gemini model in Settings.
|
||||
@@ -0,0 +1,127 @@
|
||||
id: youtube-summarizer
|
||||
title: YouTube Summarizer
|
||||
version: 0.1.0.1
|
||||
release-notes: >-
|
||||
Initial StartOS package. Download, transcribe, and summarize YouTube videos
|
||||
and podcast episodes using Google Gemini AI.
|
||||
license: Proprietary
|
||||
wrapper-repo: https://github.com/user/youtube-summarizer-startos
|
||||
upstream-repo: https://github.com/user/youtube-summarizer
|
||||
support-site: https://github.com/user/youtube-summarizer/issues
|
||||
marketing-site: https://github.com/user/youtube-summarizer
|
||||
build: ["make image"]
|
||||
|
||||
description:
|
||||
short: Download, transcribe, and summarize YouTube videos and podcasts with AI.
|
||||
long: >-
|
||||
YouTube Summarizer downloads audio from YouTube videos and podcast RSS feeds,
|
||||
transcribes them using Google Gemini, and produces structured topic-by-topic
|
||||
summaries with timestamps. Features include channel and podcast subscriptions
|
||||
with automatic new episode detection, organized history with folders,
|
||||
multiple AI model support, and a responsive web interface. Requires a
|
||||
Google Gemini API key (free tier available at aistudio.google.com/apikey).
|
||||
|
||||
assets:
|
||||
license: LICENSE
|
||||
icon: icon.png
|
||||
instructions: instructions.md
|
||||
docker-images: image.tar
|
||||
|
||||
main:
|
||||
type: docker
|
||||
image: main
|
||||
entrypoint: docker_entrypoint.sh
|
||||
args: []
|
||||
mounts:
|
||||
main: /data
|
||||
|
||||
health-checks:
|
||||
main:
|
||||
name: API health
|
||||
success-message: YouTube Summarizer is responding.
|
||||
type: docker
|
||||
image: main
|
||||
entrypoint: healthcheck.sh
|
||||
args: []
|
||||
inject: true
|
||||
|
||||
config: ~
|
||||
|
||||
dependencies: {}
|
||||
|
||||
volumes:
|
||||
main:
|
||||
type: data
|
||||
|
||||
interfaces:
|
||||
main:
|
||||
name: Web Interface
|
||||
description: Browser UI for YouTube Summarizer.
|
||||
tor-config:
|
||||
port-mapping:
|
||||
80: "3001"
|
||||
lan-config:
|
||||
443:
|
||||
ssl: true
|
||||
internal: 3001
|
||||
ui: true
|
||||
protocols: [tcp, http, https]
|
||||
|
||||
backup:
|
||||
create:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
rm -rf /backup/*
|
||||
# Back up all persistent data except temp binaries (re-downloadable)
|
||||
mkdir -p /backup/history /backup/config
|
||||
cp -a /data/history/. /backup/history/ 2>/dev/null || true
|
||||
cp -a /data/config/. /backup/config/ 2>/dev/null || true
|
||||
cp /data/cookies.txt /backup/ 2>/dev/null || true
|
||||
cp /data/.env /backup/ 2>/dev/null || true
|
||||
mounts:
|
||||
main: /data
|
||||
BACKUP: /backup
|
||||
restore:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
mkdir -p /data/history /data/config
|
||||
cp -a /backup/history/. /data/history/ 2>/dev/null || true
|
||||
cp -a /backup/config/. /data/config/ 2>/dev/null || true
|
||||
cp /backup/cookies.txt /data/ 2>/dev/null || true
|
||||
cp /backup/.env /data/ 2>/dev/null || true
|
||||
mounts:
|
||||
main: /data
|
||||
BACKUP: /backup
|
||||
|
||||
actions:
|
||||
update-ytdlp:
|
||||
name: Update yt-dlp
|
||||
description: >-
|
||||
Downloads the latest version of yt-dlp. Run this if YouTube downloads
|
||||
are failing — YouTube frequently changes its systems, requiring yt-dlp
|
||||
updates.
|
||||
warning: This may take a minute. The service will continue running.
|
||||
implementation:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
pip3 install --break-system-packages -U yt-dlp curl_cffi 2>&1
|
||||
echo "---"
|
||||
echo "yt-dlp version: $(yt-dlp --version)"
|
||||
inject: true
|
||||
Reference in New Issue
Block a user