# PinePods Documentation > A Forest of Podcasts, Rooted in the Spirit of Self-Hosting This file contains all documentation content in a single document following the llmstxt.org standard. ## AI Ad Detection Ad detection (sometimes called "ad removal") uses a language model to find **host-read ads and sponsor segments** in an episode's transcript, then lets the player **automatically skip past them** during playback. Nothing is cut from the audio file — detected ads are stored as **skip ranges**, so it's non-destructive and reversible. :::note Requires the AI container **and** a language model Ad detection needs [the AI container](./Setup.md) plus an ad-detection LLM configured in **Settings → AI**. Unlike transcription (which has a sensible default), ad detection has **no default model** — you must pick one first. See [Setup → Pull a model](./Setup.md#pull-a-model). ::: ## How it works ``` transcript ──► LLM labels ad spans ──► mapped to time ranges ──► player skips them ``` 1. Ad detection reads the episode's **transcript** (so the episode must be transcribed first — if it isn't, Pinepods transcribes it automatically as part of the job). 2. The transcript is sent to the configured **LLM**, which labels which parts are ads. 3. Those are mapped back to precise **audio time ranges** using the transcript's timings and stored as **ad skip segments**. 4. During playback, clients **seek past** any active ad segment. Because detection works from the transcript, results are approximate to within a few seconds (the boundary of a spoken segment) — which is why skipping, rather than cutting, is the right model, and why you can review and correct results (below). ## Turning it on ### Manually, per episode On an episode's **Transcript** tab, click **Detect ads with AI**. The job runs (transcribing first if needed) and detected ads then appear in the tab for review. ### Automatically, per podcast In a podcast's settings: 1. Enable **Auto-transcribe new episodes** (ad detection needs a transcript). 2. Enable **Auto-detect ads on new episodes** — this option **unlocks only when auto-transcribe is on**. 3. Choose how detected ads behave: - **Skip detected ads automatically** — ads are skipped as soon as they're found. - **Require confirmation first** — ads are found but **not** skipped until you confirm them on the episode page. ## Reviewing detected ads Open the episode's **Transcript** tab. Detected ad ranges are **highlighted** in the transcript, and a **Detected ads** list shows each range with **Confirm** / **Deny** buttons: - **Confirm** — keep skipping this ad. - **Deny** — a false positive; stop skipping it (you'll hear it). Each row shows whether it's currently **Skipping** or **Kept**. :::info Reviews are per-user Detection runs **once per episode** and the ad ranges are shared across everyone subscribed to that feed. But whether an ad is skipped — including your **Confirm/Deny** choices and the auto-skip-vs-confirm setting — is **per user**. Your decisions never affect anyone else on the server. ::: ## Choosing the model Set this in **Settings → AI → Ad-detection model**: - **Local (bundled)** — runs entirely on your server. Fully private, but **slow on CPU** and needs a 2–4 GB model file and matching RAM. Good default choice for pull: `Qwen/Qwen2.5-3B-Instruct-GGUF` → `qwen2.5-3b-instruct-q4_k_m.gguf`. - **Remote (OpenAI-compatible)** — point at an external endpoint such as [Ollama](https://ollama.com/) or an OpenAI-style cloud API. Usually **much faster**. - **Remote (Anthropic-compatible)** — point at an [Anthropic Messages API](https://docs.anthropic.com/en/api/messages) endpoint (Anthropic itself, or providers that expose that format). :::warning Remote endpoints send transcript text out With either remote option, the episode's **transcript text is sent to that service**. Local keeps everything on your server. ::: ### Example: z.ai (GLM models) [z.ai](https://z.ai/) sells GLM access in two forms, and they use **different** endpoints: | Your z.ai plan | Backend | Endpoint URL | Model | | --- | --- | --- | --- | | **GLM Coding Plan** (subscription) | **Remote (Anthropic-compatible)** | `https://api.z.ai/api/anthropic` | `glm-4.6` | | **General API** (pay-as-you-go balance) | **Remote (OpenAI-compatible)** | `https://api.z.ai/api/paas/v4` | `glm-4.5` | If you have the **Coding Plan**, you *must* use the Anthropic-compatible backend — the OpenAI-style `paas/v4` API returns "insufficient balance" because the plan's quota lives on the Anthropic endpoint. Put your z.ai API key in the **API key** field either way. Ad detection just classifies transcript text, so a cheaper/faster model tier is usually plenty — you don't need a provider's largest model. See [Setup](./Setup.md#3-the-ai-settings-page) for how to pull a local model or configure a remote endpoint. ## Client support | Client | Ad skipping | | --- | --- | | **Web** | ✅ Supported | | **Mobile (iOS/Android)** | ⏳ Not yet — planned in a future update | Detection and review happen on the server and in the web app today. Mobile skipping is on the roadmap. ## Accuracy expectations LLM ad detection is good but not perfect — host-read sponsorships blend into normal content, and boundaries land on spoken-segment edges (a few seconds of precision). That's exactly why Pinepods gives you **per-user Confirm/Deny** and a **"require confirmation first"** mode: treat auto-skip as a helpful default you can correct, not a guarantee. ## Troubleshooting - **"Ad removal: Not configured".** You haven't chosen an ad-detection model yet. Pull a local model or configure a remote endpoint in Settings → AI, then Save. - **The Detect ads button is missing.** The AI container isn't connected (check `PINEPODS_AI_URL`). - **Auto-detect can't be enabled.** Turn on **Auto-transcribe** for that podcast first. - **It's very slow / high memory.** Local CPU inference on a multi-GB model is demanding. Prefer a remote (e.g. GPU-backed Ollama) endpoint for speed. --- ## AI Features Overview Pinepods has an **optional** set of AI features that run in a separate, self-hosted container called **`pinepods-ai`**. Today they cover: - **Transcription** — turn an episode's audio into a searchable, timecoded transcript using [Whisper](https://github.com/openai/whisper) speech-to-text. - **Ad detection ("ad removal")** — use a language model to find host-read ads and sponsor segments in an episode's transcript, then let the player automatically skip past them. Both are modeled on the "optional sidecar" pattern (similar to Immich's machine-learning container): a stand-alone service that the main Pinepods server talks to over HTTP. :::note Everything here is optional and off by default If you don't run the `pinepods-ai` container (and set `PINEPODS_AI_URL`), none of these features appear — Pinepods works exactly as before. Nothing is ever transcribed or scanned for ads unless **you opt in**, either per-podcast or per-episode. ::: ## How it fits together ``` ┌────────────┐ ┌──────────────────┐ ┌───────────────┐ │ Pinepods │ HTTP │ pinepods-ai │ │ Model files │ │ server │ ─────► │ (Whisper + LLM) │ ◄────► │ /models vol │ └────────────┘ └──────────────────┘ └───────────────┘ ▲ │ │ shared, read-only │ reads downloaded audio └── downloads volume ────┘ ``` - The **Pinepods server** decides *what* to process and stores the results (transcripts, ad time-ranges) in its own database. - The **`pinepods-ai` container** is stateless. It loads the models you've chosen, reads audio from a shared read-only mount of your downloads directory, and returns results. - **Models** (Whisper weights, local LLM files) live on a persistent `/models` volume so they aren't re-downloaded on every restart. ## What you'll need - The **`pinepods-ai` container** running and reachable from the main server (see [Setup](./Setup.md)). - For **transcription**: nothing extra — a sensible Whisper model (`base`) is the default and downloads automatically on first use. - For **ad detection**: a language model. You either **pull a small local model** into the container, or point it at a **remote OpenAI-compatible endpoint** (for example [Ollama](https://ollama.com/)). See [Ad Detection](./AdDetection.md). ## Privacy & data The AI container is **fully self-hosted** by default — audio and transcripts never leave your server. The only exception is if *you* deliberately configure a **remote** LLM endpoint for ad detection that points at an external service; in that case transcript text is sent to whatever endpoint you configured. ## A note on performance These features are CPU-heavy. On a typical CPU-only host, transcribing a one-hour episode can take **many minutes**, and local ad detection adds an LLM pass on top of that. This is normal. If you have a GPU or an existing [Ollama](https://ollama.com/) server, you can make things dramatically faster — see [Setup](./Setup.md). ## Next steps - **[Setup](./Setup.md)** — deploy the container, environment variables, and the AI Settings page. - **[Transcription](./Transcription.md)** — generate and read transcripts. - **[Ad Detection](./AdDetection.md)** — detect and skip ads. --- ## Setting Up the AI Container The AI features run in the optional **`pinepods-ai`** container. This page covers deploying it, the environment variables, and the **AI Settings** page where you choose and manage models at runtime. ## 1. Run the `pinepods-ai` container The container is disabled by default in every deployment method. You enable it by: 1. Running the `pinepods-ai` service, and 2. Setting **`PINEPODS_AI_URL`** on the **main Pinepods server** so it knows where to reach it. The container needs **read-only** access to the **same downloads directory** the main server writes to, mounted at the **same path** (so file paths resolve on both sides). ### Docker Compose The bundled compose files ship with a commented-out `pinepods-ai` service and the `PINEPODS_AI_URL` variable. Uncomment both. A minimal example: ```yaml services: pinepods: environment: # Point the main server at the AI sidecar PINEPODS_AI_URL: "http://pinepods-ai:8100" # Optional shared secret — must match the sidecar's PINEPODS_AI_TOKEN if set # PINEPODS_AI_TOKEN: "a-long-random-string" # ... pinepods-ai: image: madeofpendletonwool/pinepods-ai:latest environment: WHISPER_MODEL: "base" # tiny|base|small|medium|large-v3 WHISPER_DEVICE: "cpu" # "cuda" if you use a GPU-enabled image/node WHISPER_COMPUTE_TYPE: "int8" # Ad-detection LLM defaults (usually left blank and configured from the UI): # AI_LLM_MODEL: "" # local GGUF filename under /models # AI_LLM_URL: "http://ollama:11434/v1" # AI_LLM_API_KEY: "" # AI_LLM_MODEL_NAME: "qwen2.5:3b" volumes: # SAME downloads path as the main app, read-only - /home/user/pinepods/downloads:/opt/pinepods/downloads:ro # Persistent cache for model files (Whisper weights + local LLM GGUFs) - pinepods-ai-models:/models restart: always volumes: pinepods-ai-models: ``` :::warning Mount the downloads volume at the same path The main server sends the sidecar an absolute file path (for example `/opt/pinepods/downloads/...`). The sidecar must see that exact path, so mount the same volume at the same location. A read-only (`:ro`) mount is recommended. ::: ### Kubernetes (Helm) The Helm chart has an `ai` section (disabled by default). Enable it in your values: ```yaml ai: enabled: true image: repository: madeofpendletonwool/pinepods-ai tag: latest service: port: 8100 whisper: model: "base" device: "cpu" computeType: "int8" # Ad-detection LLM defaults (optional; usually set from the UI): llm: model: "" # local GGUF filename under /models url: "" # e.g. http://ollama:11434/v1 modelName: "" # e.g. qwen2.5:3b apiKey: "" persistence: enabled: true size: 5Gi # holds Whisper weights + any local LLM models ``` When `ai.enabled` is true the chart injects `PINEPODS_AI_URL` into the main app automatically and mounts the shared downloads volume read-only into the sidecar. Raw Kubernetes manifests are also provided (`pinepods-ai.yml`) for non-Helm installs. ## 2. Environment variables **On the main Pinepods server:** | Variable | Purpose | | --- | --- | | `PINEPODS_AI_URL` | Base URL of the sidecar, e.g. `http://pinepods-ai:8100`. **Unset = all AI features disabled.** | | `PINEPODS_AI_TOKEN` | Optional shared secret sent as an `X-AI-Token` header. Set the same value on the sidecar to require it. | **On the `pinepods-ai` sidecar:** | Variable | Default | Purpose | | --- | --- | --- | | `WHISPER_MODEL` | `base` | Default transcription model (`tiny`/`base`/`small`/`medium`/`large-v3`, …). Also configurable from the UI. | | `WHISPER_DEVICE` | `cpu` | `cpu`, or `cuda` for GPU images. | | `WHISPER_COMPUTE_TYPE` | `int8` | Compute precision (`int8`, `float16`, …). | | `WHISPER_BEAM_SIZE` | `5` | Whisper beam size. | | `AI_LLM_MODEL` | *(empty)* | Default **local** LLM (GGUF filename under `/models`) for ad detection. | | `AI_LLM_URL` | *(empty)* | Default **remote** OpenAI-compatible endpoint for ad detection. | | `AI_LLM_MODEL_NAME` | *(empty)* | Default remote model id (e.g. `qwen2.5:3b`). | | `AI_LLM_API_KEY` | *(empty)* | API key for the remote endpoint, if required. | | `AI_LLM_N_CTX` | `8192` | Local LLM context window. | | `AI_LLM_MAX_TOKENS` | `1024` | Max tokens the LLM may return per request. | | `PINEPODS_AI_MODELS_DIR` | `/models` | Where model files are stored (falls back to `HF_HOME`). | | `PINEPODS_AI_MEDIA_BASE` | `/opt/pinepods/downloads` | The only directory the sidecar is allowed to read audio from. | | `PINEPODS_AI_TOKEN` | *(empty)* | Shared secret; when set, callers must send a matching `X-AI-Token`. | | `PINEPODS_AI_PORT` | `8100` | Port the sidecar listens on. | | `HF_TOKEN` | *(empty)* | Hugging Face token, only needed to pull **gated/private** model files. | :::tip Model choices are best set at runtime The `AI_LLM_*` and `WHISPER_MODEL` variables are just **initial defaults**. Day to day, you pick and change models from **Settings → AI** in the web UI (below) — no restart needed. ::: ## 3. The AI Settings page Once the container is reachable, an admin can open **Settings → AI** in the web app. It has three parts: ### Connection & capabilities - A connection indicator (**Connected** / **Not connected**). - Two capability rows: - **Transcription** — **Ready** once a Whisper model is set (it is, by default). - **Ad removal** — **Not configured** until you choose an ad-detection model (see below). ### Models - **Transcription model** — pick the Whisper model. `base` is a good default; larger models are more accurate but slower and use more memory. - **Ad-detection model** — choose the backend: - **Local (bundled)** — run a small quantized model *inside* the container. Select a model you've pulled (see next section). - **Remote (OpenAI-compatible)** — an [Ollama](https://ollama.com/) server or any OpenAI-style cloud API (URL + model + optional API key). Usually **much faster** than local CPU inference. - **Remote (Anthropic-compatible)** — an [Anthropic Messages API](https://docs.anthropic.com/en/api/messages) endpoint (Anthropic, or a provider that speaks that format such as the **[z.ai](https://z.ai/) GLM Coding Plan** — URL `https://api.z.ai/api/anthropic`, model `glm-4.6`). See [Ad Detection → Choosing the model](./AdDetection.md#choosing-the-model) for a worked z.ai example (the Coding Plan and the general API use different backends). Click **Save** to apply. The API key (for remote endpoints) is stored encrypted and never shown back. ### Pull a model To run ad detection **locally**, you first pull a model file: 1. Under **Pull a model**, choose the source: - **GGUF (Hugging Face)** — enter the repo and file, e.g. - repo: `Qwen/Qwen2.5-3B-Instruct-GGUF` - file: `qwen2.5-3b-instruct-q4_k_m.gguf` - **Whisper** — pull a specific Whisper size ahead of time. - **Ollama** — trigger an `ollama pull` on a remote Ollama server. 2. Click **Pull**. Progress shows in the **AI job queue** on the same page. 3. When it finishes, select the model under **Ad-detection model → Local** and **Save**. :::note Local models are large A useful ad-detection model is a **2–4 GB** download and needs a similar amount of RAM to run. It is not bundled into the image (that would bloat it for transcription-only users), so you pull it once and it's cached on the `/models` volume. ::: ## GPU acceleration Transcription and local LLM inference are much faster on a GPU. To use one, run a CUDA-enabled build of the sidecar on a GPU node and set `WHISPER_DEVICE: "cuda"` (and an appropriate `WHISPER_COMPUTE_TYPE`, e.g. `float16`). For ad detection specifically, pointing at a GPU-backed **remote** Ollama endpoint is often the simplest path. ## Next steps - **[Transcription](./Transcription.md)** - **[Ad Detection](./AdDetection.md)** --- ## AI Transcription With the [AI container](./Setup.md) running, Pinepods can generate a **timecoded transcript** for any episode using Whisper speech-to-text. This is separate from **built-in** transcripts that some podcasts publish in their feed — both show up in the same place. :::note Requires the AI container Transcription needs `pinepods-ai` running and `PINEPODS_AI_URL` set. Without it, the transcription controls are hidden. See [Setup](./Setup.md). ::: ## Ways to transcribe ### Manually, per episode On an episode's page, open the **Transcript** tab and click **Generate with AI**. A job is queued and you'll see live progress (transcribing a long episode takes a while on CPU). When it's done, the transcript appears in the tab. - You don't need to have downloaded the episode first — the server fetches the audio temporarily, transcribes it, and cleans up. - You can **Regenerate** at any time to replace an existing AI transcript. ### Automatically, per podcast In a podcast's settings, turn on **Auto-transcribe new episodes**. From then on, new episodes for that podcast are transcribed automatically as they arrive. - This is **opt-in per podcast** — there is no "transcribe everything" switch. - It only affects **new** episodes going forward, not your back catalog. ## Reading the transcript The **Transcript** tab shows the transcript as **timecoded segments**. Each line is timestamped, and **clicking a timestamp jumps the player** to that point — handy for skimming or finding a specific moment. If an episode has both a **built-in** (feed-provided) transcript and an **AI-generated** one, a small source selector lets you switch between them. ## How it works (and what's shared) - Transcripts are **content-level**: a given episode is transcribed **once**, and the result is shared across everyone subscribed to that feed on your server. It isn't redone per user. - The transcript is stored in the Pinepods database, so it's instantly available on later visits without re-running Whisper. - Both the full text and per-segment timings are stored, which is what powers the timecoded view — and what [ad detection](./AdDetection.md) uses to map detected ads back to precise time ranges. ## Choosing a model The Whisper model is set in **Settings → AI → Models**. Trade-offs: | Model | Speed | Accuracy | Notes | | --- | --- | --- | --- | | `tiny` / `base` | Fastest | Lower | `base` is the default; great for most uses | | `small` / `medium` | Slower | Higher | Noticeably better on tricky audio | | `large-v3` | Slowest | Best | Heavy; best with a GPU | The first time a model is used it downloads automatically and is cached on the `/models` volume. ## Tips & troubleshooting - **It's slow.** That's expected on CPU. A one-hour episode can take many minutes. Use a smaller model, or a GPU-enabled setup, if speed matters. - **The button is missing.** The AI container isn't connected — check `PINEPODS_AI_URL` and that the sidecar is healthy (Settings → AI shows the connection status). - **Nothing transcribes automatically.** Auto-transcribe is off by default; enable it per podcast. --- ## API Documentation There's actually 2 platforms that utilize APIs in Pinepods. I will make documents going over the details on both of them. ## Search API The search API is used for finding new podcasts. In order for Pinepods to search the Podcast Index, iTunes, or YouTube, it needs to be pointed at a location where it can receive information about indexed content in a format it can understand. It also lets users search these external providers without holding a private API key themselves. For those reasons, the Pinepods search container exists. It's a small Rust (Actix Web) service: you can request a free API key from the Podcast Index and host the container yourself, or just use the hosted instance at `https://search.pinepods.online/api/search`. iTunes and YouTube searches need no keys at all — YouTube is handled by a bundled `yt-dlp`, so there's no Google API key or quota to manage. See the [Search API](./search_api.md) page for full details. ## Database API The database API is how the Pinepods clients (web, desktop, and mobile) interact with the database. It is the main **Rust (Axum) API** that runs inside the primary Pinepods container — not a separate Python/FastAPI service. All clients talk to it over the same HTTP API and authenticate with **API keys**: the web UI obtains a key automatically once you sign in, while the desktop and mobile apps require you to enter your server URL and credentials when you first connect. Internally it listens on its own port and is reached through the container's nginx reverse proxy. The full endpoint reference is **generated directly from the backend source** (OpenAPI 3.1), so it stays in sync with the running code: - 📖 **[Interactive API Reference](/docs/API/reference/)** — browse every documented endpoint here. - 🧪 **Live docs on your own server** — visit `/api/docs` on your PinePods instance for an always-current interactive UI, or fetch the raw spec at `/api/openapi.json`. Continue on into the documentation pages for these APIs to get an understanding of how they work and how to access data over each of them. --- ## Database API Reference :::tip This page has moved The PinePods Database API reference is now **generated automatically from the backend source code**, so it always matches the running server instead of drifting out of date. 👉 **[Open the interactive API Reference »](/docs/API/reference/)** ::: ## What changed This page used to be a large, hand-maintained list of endpoints. The PinePods API has grown to hundreds of endpoints, and keeping a hand-written page accurate became impossible. Instead, the backend now emits a standard **OpenAPI 3.1** specification straight from the code ([`utoipa`](https://docs.rs/utoipa)), and this site renders it. - **Interactive reference:** [/docs/API/reference/](/docs/API/reference/) - **Raw OpenAPI spec:** [`/openapi.json`](/openapi.json) (also served by any running PinePods server at `/api/openapi.json`) - **Live docs on your own server:** browse to `/api/docs` on your PinePods instance for an always-up-to-date interactive UI. ## Authentication (quick reference) Most endpoints require an API key tied to a user account, sent in the **`Api-Key`** header. Admin-only endpoints additionally require an admin (or web) key. See the [API introduction](./api_intro.md) for how keys are issued to the web, desktop, and mobile clients. > **Note:** the reference is rolling out across the API module-by-module, so some > endpoints may not appear yet. The spec is regenerated on every change and verified in > CI, so what *is* listed is guaranteed accurate. --- ## PinePods Search API Documentation ## 🔍 Overview The PinePods Search API is a high-performance Rust-based Actix Web application that provides comprehensive podcast and YouTube channel discovery capabilities. The API supports multiple search providers and offers detailed content information retrieval. ### ✨ Key Features - **Multi-Provider Search**: PodcastIndex, iTunes, and YouTube (YouTube is powered by a bundled `yt-dlp` — **no Google/YouTube API key or quota required**) - **Flexible Search Types**: Search by podcast title, person/host, or YouTube channels - **Real-time Statistics**: Built-in usage tracking and analytics - **High Performance**: Rust-based with async processing - **CORS Enabled**: Ready for web application integration - **Containerized**: Docker-ready deployment --- ## 🚀 Quick Start ### Getting Required API Keys - **PodcastIndex API** (Recommended): [Get free API credentials](https://api.podcastindex.org/) - **Docker**: For containerized deployment YouTube search needs **no API key** — the container bundles `yt-dlp`, which queries YouTube directly. iTunes search also requires no key. ### Environment Configuration Create an environment file with your API credentials: ```bash # Required for PodcastIndex searches (iTunes and YouTube need no keys) API_KEY=your_podcastindex_api_key API_SECRET=your_podcastindex_api_secret # Optional: Logging level RUST_LOG=info ``` :::info YouTube uses yt-dlp, not the Google API Earlier versions of this API used the YouTube Data API v3 and a `YOUTUBE_API_KEY`. That is **no longer the case** — YouTube search and channel lookups now shell out to `yt-dlp`, which the Docker image installs automatically. There is no API key to manage and no daily quota to hit. If you build a custom image, make sure `yt-dlp` is on the `PATH` or YouTube features will return a `yt-dlp not available` error. ::: ### Docker Deployment ```yaml version: '3.8' services: pinepods-search-api: image: madeofpendletonwool/pinepods_backend:latest container_name: pinepods-search-api env_file: .env ports: - "5000:5000" restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5000/api/search"] interval: 30s timeout: 10s retries: 3 ``` ### PinePods Integration Update your PinePods configuration: ```yaml # For local deployment API_URL: 'http://localhost:5000/api/search' # For production with domain API_URL: 'https://your-domain.com/api/search' ``` --- ## 📚 API Reference ### Base URL ``` http://localhost:5000 ``` ### Authentication The API handles authentication automatically using configured environment variables. No additional authentication headers are required from clients. --- ## 🔗 Endpoints ### 1. Universal Search **Endpoint:** `GET /api/search` **Description:** Search for podcasts across multiple providers or YouTube channels #### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `query` | string | Yes* | - | Search term or query | | `index` | string | No | `podcastindex` | Search provider: `podcastindex`, `itunes`, or `youtube` | | `search_type` | string | No | `term` | Search type: `term` or `person` (PodcastIndex only) | *When both `query` and `index` are omitted, returns a health check response. #### Provider-Specific Features ##### PodcastIndex (Recommended) - **Term Search**: `/search/byterm` - General podcast search - **Person Search**: `/search/byperson` - Search by host/person name - **Advanced Metadata**: Rich podcast information - **Privacy Focused**: No user tracking ##### iTunes - **Term Search Only**: Basic podcast discovery - **Limited Metadata**: Standard iTunes podcast data ##### YouTube - **Channel Search**: Discover YouTube channels (results are deduplicated by channel, up to ~25) - **Powered by yt-dlp**: No API key or quota required - **Thumbnails & recent videos**: Channel details include the most recent videos (see the `/api/youtube/channel` endpoint) #### Example Requests ```bash # Health Check curl -X GET 'http://localhost:5000/api/search' # Returns: "Test connection successful" # PodcastIndex Term Search curl -X GET 'http://localhost:5000/api/search?query=python%20podcast&index=podcastindex' # PodcastIndex Person Search curl -X GET 'http://localhost:5000/api/search?query=joe%20rogan&index=podcastindex&search_type=person' # iTunes Search curl -X GET 'http://localhost:5000/api/search?query=tech%20news&index=itunes' # YouTube Channel Search curl -X GET 'http://localhost:5000/api/search?query=programming&index=youtube' ``` --- ### 2. Podcast Details **Endpoint:** `GET /api/podcast` **Description:** Retrieve detailed information for a specific podcast using its feed ID #### Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | PodcastIndex feed ID | #### Example Request ```bash curl -X GET 'http://localhost:5000/api/podcast?id=920666' ``` --- ### 3. YouTube Channel Details **Endpoint:** `GET /api/youtube/channel` **Description:** Get YouTube channel information and its most recent videos (up to 15), fetched via `yt-dlp`. #### Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | YouTube Channel ID | :::note `subscriberCount` and `videoCount` are part of the response shape but are **not currently populated** by the `yt-dlp` flat fetch — they are returned as `null`. The `recentVideos` array (id, title, description, url, thumbnail, `publishedAt`, and a `PT#M#S` ISO-8601 `duration`) is the data PinePods actually uses. ::: #### Example Request ```bash curl -X GET 'http://localhost:5000/api/youtube/channel?id=UCXuqSBlHAE6Xw-yeJA0Tunw' ``` --- ### 4. API Statistics **Endpoint:** `GET /api/stats` **Description:** Retrieve real-time API usage statistics and metrics #### Example Request ```bash curl -X GET 'http://localhost:5000/api/stats' ``` --- ## 📄 Response Formats ### PodcastIndex Search Response ```json { "status": "true", "feeds": [ { "id": 920666, "title": "Python Bytes", "url": "https://pythonbytes.fm/episodes/rss", "originalUrl": "https://pythonbytes.fm/episodes/rss", "link": "https://pythonbytes.fm", "description": "Python Bytes is a weekly podcast...", "author": "Michael Kennedy and Brian Okken", "ownerName": "Michael Kennedy", "image": "https://pythonbytes.fm/static/img/podcast-logo.png", "artwork": "https://pythonbytes.fm/static/img/podcast-logo.png", "lastUpdateTime": 1640995200, "lastCrawlTime": 1640995800, "lastParseTime": 1640995850, "lastGoodHttpStatusTime": 1640995900, "lastHttpStatus": 200, "contentType": "application/rss+xml", "itunesId": 1173964558, "generator": "custom", "language": "en", "type": 0, "dead": 0, "crawlErrors": 0, "parseErrors": 0 } ], "count": 25, "query": "python podcast", "description": "Found matching feeds." } ``` ### iTunes Search Response ```json { "resultCount": 25, "results": [ { "wrapperType": "track", "kind": "podcast", "collectionId": 1173964558, "trackId": 1173964558, "artistName": "Michael Kennedy and Brian Okken", "collectionName": "Python Bytes", "trackName": "Python Bytes", "collectionCensoredName": "Python Bytes", "trackCensoredName": "Python Bytes", "collectionViewUrl": "https://podcasts.apple.com/us/podcast/python-bytes/id1173964558", "feedUrl": "https://pythonbytes.fm/episodes/rss", "trackViewUrl": "https://podcasts.apple.com/us/podcast/python-bytes/id1173964558", "artworkUrl30": "https://is1-ssl.mzstatic.com/image/thumb/Podcasts123/v4/f4/89/c4/f489c4e7-35cb-474d-bf4f-0ccf67e861b0/mza_2029009828340268613.jpg/30x30bb.jpg", "artworkUrl60": "https://is1-ssl.mzstatic.com/image/thumb/Podcasts123/v4/f4/89/c4/f489c4e7-35cb-474d-bf4f-0ccf67e861b0/mza_2029009828340268613.jpg/60x60bb.jpg", "artworkUrl100": "https://is1-ssl.mzstatic.com/image/thumb/Podcasts123/v4/f4/89/c4/f489c4e7-35cb-474d-bf4f-0ccf67e861b0/mza_2029009828340268613.jpg/100x100bb.jpg", "collectionPrice": 0.00, "trackPrice": 0.00, "releaseDate": "2024-01-15T08:00:00Z", "collectionExplicitness": "cleaned", "trackExplicitness": "cleaned", "trackCount": 350, "trackTimeMillis": 1800000, "country": "USA", "currency": "USD", "primaryGenreName": "Technology", "contentAdvisoryRating": "Clean", "genreIds": ["1318", "26", "1528"] } ] } ``` ### YouTube Channel Search Response ```json { "results": [ { "channelId": "UCXuqSBlHAE6Xw-yeJA0Tunw", "name": "Linus Tech Tips", "description": "We make videos and stuff, cool eh?", "thumbnailUrl": "https://yt3.ggpht.com/ytc/AKedOLQDwRAKGBtB4wWJKcAABhCRYrvhSGJr5yLO=s240-c-k-c0x00ffffff-no-rj", "url": "https://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw" } ] } ``` ### YouTube Channel Details Response ```json { "channelId": "UCXuqSBlHAE6Xw-yeJA0Tunw", "name": "Linus Tech Tips", "description": "We make entertaining videos about technology...", "thumbnailUrl": "https://yt3.ggpht.com/ytc/AKedOLQDwRAKGBtB4wWJKcAABhCRYrvhSGJr5yLO=s800-c-k-c0x00ffffff-no-rj", "url": "https://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw", "subscriberCount": 15400000, "videoCount": 6000, "recentVideos": [ { "id": "dQw4w9WgXcQ", "title": "Latest Tech Review", "description": "Today we're looking at...", "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/mqdefault.jpg", "publishedAt": "2024-01-15T10:00:00Z", "duration": "PT10M30S" } ] } ``` ### API Statistics Response ```json { "api_usage": { "itunes_hits": 1250, "podcast_index_hits": 3420, "youtube_hits": 890, "total_hits": 5560 }, "timestamp": "2024-01-15T14:30:00.000Z" } ``` --- ## ⚠️ Error Handling ### HTTP Status Codes | Status Code | Description | Common Causes | |-------------|-------------|---------------| | `200` | Success | Request completed successfully | | `400` | Bad Request | Invalid parameters or malformed request | | `404` | Not Found | Resource not found (podcast ID, channel ID) | | `500` | Internal Server Error | API credentials missing, external API failure | | `503` | Service Unavailable | External API rate limiting or downtime | ### Error Response Format Errors are returned as a **plain-text body** with the relevant HTTP status code (most failures are `500`), not as a JSON envelope. For example: ``` API_KEY not set ``` ### Common Error Messages - `"API_KEY not set"` - PodcastIndex API key missing - `"API_SECRET not set"` - PodcastIndex API secret missing - `"yt-dlp not available"` - `yt-dlp` is not installed / not on the `PATH` - `"yt-dlp search failed"` - YouTube channel search via `yt-dlp` failed - `"yt-dlp channel fetch failed"` - Fetching a channel's videos via `yt-dlp` failed - `"Channel not found or has no videos"` - YouTube channel ID invalid or empty - `"Failed to parse response body"` - External API returned invalid data --- ## 🔧 Configuration Reference ### Environment Variables | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `API_KEY` | Yes (for PodcastIndex) | - | PodcastIndex API Key | | `API_SECRET` | Yes (for PodcastIndex) | - | PodcastIndex API Secret | | `RUST_LOG` | No | `info` | Logging level (`error`, `warn`, `info`, `debug`, `trace`) | iTunes and YouTube require no environment configuration — iTunes is keyless and YouTube is served by the bundled `yt-dlp`. ### Network Configuration - **Port**: `5000` (configurable in source) - **Binding**: `0.0.0.0:5000` (all interfaces) - **CORS**: Enabled for all origins (self-hosted friendly) - **Timeout**: 30 seconds for external API calls - **User-Agent**: `PodPeopleDB/1.0` --- ## 💡 Best Practices ### Search Provider Selection 1. **PodcastIndex** (Recommended) - ✅ Privacy-focused, no tracking - ✅ Rich metadata and advanced search - ✅ Person/host search capability - ✅ Open-source friendly - ✅ Fast and reliable 2. **iTunes** - ✅ No API key required - ❌ Limited search capabilities - ❌ Basic metadata only - ❌ Apple ecosystem focused 3. **YouTube** - ✅ Video content discovery - ✅ No API key required (uses bundled `yt-dlp`) - ✅ Rich media thumbnails and recent videos - ❌ Subject to YouTube's own rate limiting / anti-bot measures; keep `yt-dlp` updated ### Performance Optimization - **Caching**: Implement client-side caching for frequently accessed content - **Rate Limiting**: Respect external rate limits (PodcastIndex: no limit; YouTube: no API quota, but YouTube may throttle scraping — keep `yt-dlp` current) - **Batch Requests**: Use appropriate search result limits (max 25-50 results) - **Error Handling**: Implement retry logic with exponential backoff ### Security Considerations - **API Keys**: Store in environment variables, never in code - **CORS**: Configure appropriately for your domain in production - **HTTPS**: Use HTTPS in production deployments - **Input Validation**: Sanitize search queries on the client side --- ## 🔍 Troubleshooting ### Common Issues #### "API_KEY not set" Error ```bash # Check environment variables are loaded docker exec -it pinepods-search-api env | grep API # Verify .env file format (no spaces around =) API_KEY=your_key_here API_SECRET=your_secret_here ``` #### No Search Results ```bash # Test API connectivity curl -v http://localhost:5000/api/search # Check specific provider curl -v "http://localhost:5000/api/search?query=test&index=podcastindex" ``` #### YouTube Search Not Working ```bash # Test a YouTube search curl -v "http://localhost:5000/api/search?query=test&index=youtube" # Confirm yt-dlp is installed and on PATH inside the container docker exec -it pinepods-search-api yt-dlp --version # A "yt-dlp not available" response means yt-dlp is missing from the image. # Persistent failures usually mean yt-dlp is out of date — update it: docker exec -it pinepods-search-api yt-dlp -U ``` ### Logging and Monitoring ```bash # View API logs docker logs pinepods-search-api # Follow logs in real-time docker logs -f pinepods-search-api # Set debug logging # In .env file: RUST_LOG=debug ``` ### Health Checks ```bash # Basic health check curl http://localhost:5000/api/search # Expected: "Test connection successful" # API statistics curl http://localhost:5000/api/stats # Expected: JSON with usage statistics ``` --- ## 📈 Monitoring and Analytics The API provides built-in usage tracking accessible via the `/api/stats` endpoint: - **Request Counting**: Tracks usage per provider - **Real-time Statistics**: Live usage data - **Timestamp Tracking**: When statistics were generated - **Total Aggregation**: Combined usage across all providers Integrate with your monitoring solution: ```bash # Prometheus metrics endpoint (manual implementation) curl http://localhost:5000/api/stats # Example integration with monitoring script #!/bin/bash STATS=$(curl -s http://localhost:5000/api/stats) echo "pinepods_api_total_requests $(echo $STATS | jq '.api_usage.total_hits')" ``` --- ## 🚀 Production Deployment ### Docker Compose (Production) ```yaml version: '3.8' services: pinepods-search-api: image: madeofpendletonwool/pinepods_backend:latest container_name: pinepods-search-api env_file: .env.production ports: - "127.0.0.1:5000:5000" # Bind to localhost only restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5000/api/search"] interval: 30s timeout: 10s retries: 3 start_period: 60s logging: driver: "json-file" options: max-size: "10m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M reservations: cpus: '0.25' memory: 128M ``` ### Reverse Proxy (Nginx) ```nginx server { listen 80; server_name api.yourdomain.com; location /api/ { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # CORS headers (if needed) add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # Caching for static responses location /api/stats { expires 30s; add_header Cache-Control "public, no-transform"; } } } ``` --- *This documentation covers PinePods Search API v1.0. For the latest updates and additional information, visit the [PinePods GitHub repository](https://github.com/madeofpendletonwool/PinePods).* --- ## Container Fundamentals ## Overview PinePods ships as a **single Docker image** that runs several cooperating processes under a lightweight process supervisor. Everything an instance needs at runtime — the web UI, the main API, the gpodder sync server, and the reverse proxy — lives in that one container. It talks to two external services you provide: a **database** (PostgreSQL or MySQL/MariaDB) and a **Valkey/Redis** cache. This page documents how the container is put together and what a "native" (non-Docker) deployment would need to replicate. :::note Rewritten for the Rust stack PinePods used to run a Python/FastAPI backend supervised by `supervisord`, with feed refreshes driven by cron. **That is no longer the case.** The backend is now a Rust (Axum) API, processes are supervised by [Horust](https://github.com/FedericoPonzi/Horust), and background jobs run on an internal scheduler — there is no cron and no Python runtime in the final image. ::: ## Core Components ### 1. Frontend — Rust / Yew (WebAssembly) - Built with the [Yew](https://yew.rs) framework and compiled to **WebAssembly (WASM)** with [Trunk](https://trunkrs.dev). - Shipped as static files (HTML/JS/WASM/CSS) and served directly by nginx from `/var/www/html`. There is no Node.js server involved. - The desktop and mobile clients are separate apps; this is the browser UI. ### 2. Backend — Rust API (Axum) The main backend is a compiled Rust binary, `pinepods-api`. It handles: - All data and business logic (`/api/*` endpoints) - Podcast feed parsing, refresh, and downloads - User management, authentication, and OIDC - RSS feed generation (`/api/feed/*`) - WebSocket connections for real-time updates and task progress - **Background job scheduling** — feed refreshes and nightly maintenance run on an internal scheduler inside this process (no cron) It listens on **port 8032 inside the container** and is reached through nginx; it is not exposed directly. ### 3. gpodder API — Go A separate Go binary, `gpodder-api`, implements the gpodder.net sync protocol so apps like AntennaPod can sync subscriptions and episode actions with PinePods. It listens on **port 8042** and shares the same database as the Rust API. ### 4. Database setup tool — `pinepods-db-setup` Schema creation, migrations, and validation are performed by a small standalone binary, `pinepods-db-setup`. It is written in Python but **compiled to a single executable with PyInstaller at build time**, so the runtime image contains no Python interpreter. It runs **once on every startup** before the services launch, is idempotent, and supports both PostgreSQL and MySQL/MariaDB. ### 5. Database layer (external) Supports **PostgreSQL** (recommended) and **MySQL/MariaDB**. Stores users, podcast and episode metadata, listening history, playlists, settings, queue, downloads, and gpodder sync state. You run this yourself (or via the bundled Helm/Compose examples); it is not part of the PinePods image. ### 6. Valkey / Redis cache (external) Used for caching and coordination. Configured via `VALKEY_HOST` / `VALKEY_PORT`. ### 7. nginx nginx listens on **port 8040** (the web UI port) and: - Serves the compiled WASM frontend (with the correct `application/wasm` MIME type) - Reverse-proxies API, RSS, and WebSocket routes to the Rust API - Routes gpodder.net protocol paths to the Go service - Adds CORS headers and handles preflight requests ## Process Supervision — Horust `startup.sh` is the container entrypoint. It prepares the environment, runs the database setup binary, and then hands off to **Horust**, which supervises the long-running services defined in `/etc/horust/services/`: | Service | Binary | Port | Notes | |---|---|---|---| | `pinepods-api` | `/usr/local/bin/pinepods-api` | 8032 (internal) | Main Rust API + internal scheduler | | `gpodder-api` | `/usr/local/bin/gpodder-api` | 8042 | Starts after `pinepods-api` | | `nginx` | `nginx -g 'daemon off;'` | 8040 | Starts after `gpodder-api` | Each service is configured to restart automatically. Startup ordering is enforced with `start-after` so the API is up before nginx begins proxying to it. ### Non-root execution (PUID / PGID) When `PUID` and `PGID` are set, `startup.sh` remaps the runtime `pinepods` user to those IDs and uses `su-exec` to drop privileges, so the **entire stack runs as your host user** and downloaded files are owned correctly. A one-time recursive permission migration is gated by a marker file on the downloads volume, so subsequent boots are instant. If `PUID`/`PGID` are unset, the stack runs as root (legacy mode). ## Routing (nginx) nginx (port 8040) maps request paths to the right backend: | Path | Destination | Purpose | |---|---|---| | `/` | static files in `/var/www/html` | The WASM web UI (`try_files … /index.html`) | | `/api/*` | Rust API (8032) | Main application API | | `/api/gpodder` | Rust API (8032) | gpodder bridge handled by the Rust API | | `/ws/api/data/`, `/ws/api/tasks/` | Rust API (8032) | WebSocket connections | | `/rss/{id}` | rewritten to `/api/feed/{id}` → Rust API (8032) | Public RSS feeds | | `/api/2`, `/auth`, `/subscriptions`, `/devices`, `/updates`, `/episodes`, `/settings`, `/lists`, `/favorites`, `/sync-devices`, … | Go gpodder API (8042) | gpodder.net protocol | ## Ports - **8040** — web UI (nginx). **Exposed**; this is the port you publish. - **8042** — gpodder API (Go). **Exposed** for direct gpodder clients. - **8032** — Rust API. **Internal only**, reached via nginx. The container `HEALTHCHECK` hits `http://localhost:8040/api/health`, which proxies to the Rust API and verifies database connectivity. ## Authentication PinePods uses **API-key-based authentication** for client/server calls. Keys are managed in the database through the API. :::caution Removed Older versions wrote a web API key to `/tmp/web_api_key.txt` on startup. **This file is no longer created** — it was removed for security. Don't rely on it. ::: ## Background Jobs Feed refreshes and nightly maintenance are **scheduled internally by the Rust API**. The old cron jobs and helper scripts (`call_refresh_endpoint.sh`, `call_nightly_tasks.sh`) and their `*/30 * * * *` crontab entries have been **removed**. Refresh cadence is configurable through PinePods' settings rather than the crontab. ## Build Process (multi-stage Dockerfile) The image is built in several stages and assembled into a small Alpine final image: 1. **Web (rust:alpine)** — builds the Yew app to WASM: ```bash rustup target add wasm32-unknown-unknown RUSTFLAGS="--cfg=web_sys_unstable_apis --cfg getrandom_backend=\"wasm_js\"" \ trunk build --features server_build --release ``` Output (`/app/dist`) is copied to `/var/www/html`. 2. **gpodder (golang:alpine)** — `go build` produces the static `gpodder-api` binary. 3. **db-setup (python:3.11-alpine)** — PyInstaller compiles `setup_database_new.py` (plus `database_functions/`) into the standalone `pinepods-db-setup` binary. 4. **rust-api (rust:alpine)** — `cargo build --release` produces the statically linked `pinepods-api` binary. 5. **Final (alpine)** — installs runtime tools (nginx, ffmpeg, yt-dlp, db clients, `su-exec`, Horust), copies the four artifacts and the startup files, and sets `startup.sh` as the entrypoint. ## Container Directory Structure ``` /usr/local/bin/ ├── pinepods-api # Rust API (Axum) ├── gpodder-api # Go gpodder.net sync server ├── pinepods-db-setup # Compiled DB setup/migration tool ├── horust # Process supervisor └── yt-dlp # YouTube media fetching /var/www/html/ # Compiled WASM frontend (served by nginx) /etc/horust/services/ # *.toml service definitions (copied from startup/services) /etc/nginx/nginx.conf # nginx config /pinepods/ ├── startup/ # startup.sh, services/, nginx.conf, setup_database_new.py ├── database_functions/ # migration definitions (source) ├── clients/ ├── cache/ └── current_version /opt/pinepods/ ├── downloads/ # downloaded episodes (persist this) ├── backups/ # backups (persist this) ├── certs/ └── local-media/ # user-mounted local podcast library /var/log/pinepods/service.log # Horust service logs (production mode) ``` ## Required Environment Variables ```bash # Database DB_TYPE= DB_HOST= DB_PORT= DB_USER= DB_PASSWORD= DB_NAME= # Cache VALKEY_HOST= VALKEY_PORT= # Server / behavior HOSTNAME= SEARCH_API_URL= PEOPLE_API_URL= DEBUG_MODE= TZ= # Optional first-boot admin (otherwise you're prompted in the UI) FULLNAME= USERNAME= EMAIL= PASSWORD= # Optional non-root execution PUID= PGID= ``` OIDC/SSO adds a family of `OIDC_*` variables (provider name, client id/secret, endpoint URLs, claim mappings). See the [OIDC setup guide](../tutorial-extras/OIDC-setup.md). ## Running Without Docker (native) To run PinePods natively you would reproduce what the container does: 1. **Provide a database** (PostgreSQL or MySQL/MariaDB) and a **Valkey/Redis** instance, and set the environment variables above. 2. **Run the database setup** once on startup (idempotent) — the compiled `pinepods-db-setup`, or the equivalent `setup_database_new.py` with `database_functions/` available. 3. **Start `pinepods-api`** (listens on 8032). Its internal scheduler handles feed refresh and nightly tasks — no cron needed. 4. **Start `gpodder-api`** (listens on 8042) if you want gpodder sync. 5. **Serve the WASM frontend and reverse-proxy the APIs** with nginx using the routing table above (UI on 8040). 6. Optionally use a supervisor (the container uses Horust) to keep the three services running and ordered. :::tip Connecting over a Unix socket On a bare-metal install you can point PinePods at a local database over a Unix domain socket instead of TCP. Set `DB_HOST` to the socket **directory** (an absolute path beginning with `/`) rather than a hostname or IP: ```bash # PostgreSQL default socket directory DB_HOST=/var/run/postgresql DB_PORT=5432 ``` Keep `DB_PORT` set — PostgreSQL names its socket file `.s.PGSQL.`, so the port still selects the right socket. Any `DB_HOST` value starting with `/` is treated as a socket path; anything else is treated as a TCP host. This works for both PostgreSQL and MySQL/MariaDB. ::: ## Logging & Debug Mode In production, Horust writes service output to `/var/log/pinepods/service.log`. Set: ```bash DEBUG_MODE=true ``` to switch Horust into stdout/stderr mode so all service logs stream directly to the container's standard output (handy for `docker logs`) along with extra diagnostic detail. --- ## Developing First of all, thanks for considering contributing on Pinepods! Pinepods is a Rust project — the frontend uses the Yew framework to build a WASM application, and the backend is a Rust (Axum) API that serves data from the database of the user's choice. A separate Go service provides gpodder.net sync. For a deeper look at how the pieces fit together at runtime, see [Container Fundamentals](./Container-Fundamentals.md). This article outlines how to get Pinepods running in a development environment, and outlines the basics of the architecture. - [Setting up the Development Environment](#setting-up-the-dev-environment) - [Prerequisites](#prerequisites) - [Running the App](#running-the-project) - [Notes](#notes) - [Git Strategy](#git-strategy) - [Flow](#git-flow) - [Branches](#git-branch-naming) - [PR Guidelines](#pr-guidelines) - [Resources for Beginners](#resources-for-beginners) ## Setting up the Dev Environment ### Prerequisites You will need either the latest version of **[Rust](https://www.rust-lang.org/tools/install)**. You'll also need the latest version of **[Trunk](https://trunkrs.dev/)** to build and serve the application. Finally **[Git](https://git-scm.com/downloads)** to easily fetch the code, and push any changes. If you plan on running or deploying the container, you'll also need **[Docker](https://docs.docker.com/get-docker/)**. With all this installed you also need the compilation target for wasm ``` rustup target add wasm32-unknown-unknown ``` ### Running the Project 1. Get Code: `git clone https://github.com/madeofpendletonwool/PinePods.git` 2. Navigate into the directory: `cd web` 4. Start dev server: `RUSTFLAGS="--cfg=web_sys_unstable_apis" trunk serve --features server_build --release` Pinepods should now be being served on [Localhost Port 8080](http://localhost:8080/). Hot reload is enabled, so making changes to any of the files and saving will trigger them to be rebuilt and the page refreshed. Now, what you've just done is run the web frontend of the project. The backend is not running currently, meaning, unless you connect to an external Pinepods server you will not be able to sign in. To sign in you need the backend running. To run the backend you can either just pull the Pinepods docker image form docker hub or you can build it yourself. You can build it with this command after navigating to the base repo directory: ``` cd Pinepods/ sudo docker build -t madeofpendletonwool/pinepods:latest . ``` Then once built you can run the container with **[Docker Compose](https://github.com/madeofpendletonwool/PinePods/tree/main/deployment/docker/compose-files)**. Once you have the backend running you can connect to the server and sign in with your development frontend. Go to the development server url: http://localhost:8080 by default. Click the connect to different server button: ![Connect Different Server Button](/img/diff-serv.png) And then enter the server url in the server name: http://localhost:8040 by default with the compose file linked above. You're now signed into a dev Pinepods server using a local backend! ### Notes - You'll notice above we're using the server_build feature. This is because when compiling without that feature it builds the project for the client version which builds on Tauri. --- ## Git Strategy ### Git Flow Like most Git repos, we are following the [Github Flow](https://guides.github.com/introduction/flow) standard. 1. Create a fork 2. Make any changes you want 🧑‍💻 3. Add, commit and push your changes to your branch/ fork 4. Head over to GitHub and create a Pull Request 5. Hit submit 6. Follow up with any reviews on your code 7. Merge 🎉 Please limit PRs to one feature/bug fix per PR. This will make it less complicated to merge your code if there's a problem with one thing but not the other. ### Git Branch Naming The format of your branch name should be something similar to: `[TYPE]/[PR] [TITLE]` For example, `FEATURE/Awesome feature` or `FIX/login server error` ### PR Guidelines Once you've made your changes, and pushed them to your fork or branch, you're ready to open a pull request! For a pull request to be merged, it must: - Must be backwards compatible - The build and tests (run by GH actions) must pass - There must not be any merge conflicts When you submit your PR, include some required info. Including: - A brief description of your changes - The issue or discussion number (if applicable) - For UI related updates include a screenshot - If any dependencies were added, explain why it was needed, state the cost associated, and confirm it does not introduce any security issues - Finally hit submit! --- ## Resources for Beginners New to Rust web development? Glad you're here! The following articles should point you in the right direction for getting up to speed with the technologies used in this project: - [Open Source for Beginners](https://opensource.guide/how-to-contribute/) - [Tutorial for Yew](https://yew.rs/docs/tutorial) - [The Rust Book](https://doc.rust-lang.org/book/) - [Axum (backend web framework)](https://docs.rs/axum/latest/axum/) - [Complete beginners guide to Docker](https://docker-curriculum.com/) - [Docker Classroom - Interactive Tutorials](https://training.play-with-docker.com/) - [Git cheat sheet](http://git-cheatsheet.com/) As well as Rust, Yew, Git and Docker- you'll also need an IDE (e.g. [VS Code](https://code.visualstudio.com/) or [Vim](https://www.vim.org/)) and a terminal (Windows users may find [WSL](https://docs.microsoft.com/en-us/windows/wsl/) more convenient). --- --- ## Docs Versioning The documentation site is versioned so that each PinePods release keeps its own frozen doc set, selectable from the **version dropdown** in the top-left of the navbar (similar to the Talos Linux docs). This page explains how versioning works here and how to cut a new version at release time. ## How it works The site is built with [Docusaurus](https://docusaurus.io/) and uses its built-in [docs versioning](https://docusaurus.io/docs/versioning): - The live `docs/` folder is always the **current (unreleased) version**, shown in the dropdown as **"Next 🚧"** with an *unreleased* banner. This is where all in-progress edits go. - Cutting a version **snapshots** `docs/` into `versioned_docs/version-X.Y.Z/`, snapshots `sidebars.js` into `versioned_sidebars/`, and appends the version to `versions.json`. - The **newest entry in `versions.json` is served as the default** at `/docs/`. The current/"Next" version is never in `versions.json`, so it is never the default — visitors always land on the latest *released* version. - The navbar, theme, CSS, and site config are **global** — they are shared across every version. Only the Markdown content is frozen per version, so any site improvement (new dropdown entries, styling, etc.) applies to all versions at once. :::note API reference The interactive API reference at `/docs/API/reference/` is generated from the OpenAPI spec by a separate plugin and is **not** versioned — it always reflects the current API. The API *Markdown* pages under `docs/API/` are versioned like the rest of the docs. ::: ## Cutting a new version at release time When PinePods ships a new release (e.g. `0.9.1`): 1. Make sure `docs/` reflects the docs for that release. 2. Cut the version: ```bash npm run docusaurus docs:version 0.9.1 ``` 3. Update the current-version label in `docusaurus.config.js` to the next in-progress version, e.g.: ```js versions: { current: { label: "0.9.2 (Next 🚧)", path: "next", banner: "unreleased", }, }, ``` 4. Commit the generated files — `versioned_docs/version-0.9.1/`, `versioned_sidebars/version-0.9.1-sidebars.json`, and the updated `versions.json` — along with the config change. 5. Rebuild and deploy the Docker image as usual. After this, `versions.json` becomes `["0.9.1", "0.9.0"]`: `0.9.1` automatically becomes the default, `0.9.0` drops down the dropdown with an "old version" banner, and `docs/` continues as the next unreleased set. :::tip As the number of versions grows, dev builds can be sped up with [`onlyIncludeVersions`](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-docs#onlyIncludeVersions) in the docs plugin config. ::: --- ## Auto-Download Auto-download keeps the podcasts you care about ready for offline listening automatically. When enabled for a podcast, **new episodes are queued for download as soon as they're discovered during a refresh** — no manual tapping required. ## Enabling auto-download Auto-download is a **per-podcast** setting, so you choose exactly which shows download automatically. - **Web** — open a podcast and use its Download Settings to toggle auto-download on. - **Mobile** — open the podcast detail screen and enable auto-download there. ## How it behaves - During each scheduled podcast refresh, PinePods checks your auto-download podcasts for new episodes and enqueues any it finds for download. - Downloads run in the background and won't block the rest of the app. - Episodes you already have, or have already played, are not re-downloaded. ## Good to know - Auto-download respects the server's download settings — if downloads are disabled globally, auto-download won't queue anything. - Pair auto-download with a **smart playlist** (for example "Fresh Releases") so new episodes are both downloaded and surfaced in a ready-to-play list. - Combine with [Serial Podcasts](./SerialPodcasts.md) for narrative shows you want downloaded and played in order. --- ## Chapters Pinepods supports Chapters as defined by the PodcastIndex Namespace. You won't need to do anything special to take advantage of this really helpful feature. Any podcast episode that you play through podcast will automatically pick up the chapters in the player as seen below: ![Chapters Button](/img/chapters.png) Clicking the button will show you all the episode chapters. You can click them to skip ahead to a chapter in the episode from there ![Chapters Display](/img/chapter-show.png) --- ## Custom Theme Creator PinePods ships with many built-in themes, but if none of them is quite right, the **Custom Theme Creator** lets you build your own color scheme from scratch. ![PinePods ships with many built-in themes](/img/screenshots/tonsofthemes.png) > Looking to just switch between the built-in themes? See > [Theming](../tutorial-basics/Theming.md). This page covers building a brand-new theme. ## Creating a theme Open the **Custom Theme Creator** in Settings and adjust the theme's colors to taste. As you change colors, the theme updates so you can dial in exactly the look you want — backgrounds, accents, text, and the rest of the palette. ## Where your theme applies Your custom theme is part of your user settings, so it follows your account across devices, just like the built-in themes. Each user on the server picks their own theme, so your color scheme is yours alone. ## Tips - Start from the built-in theme closest to what you want, then tweak — it's faster than building a palette from a blank slate. - Aim for enough contrast between text and background colors so show notes and episode lists stay easy to read. --- ## Downloads Download episodes to keep them for offline listening — on a flight, a commute, or anywhere without a reliable connection. Downloaded episodes are stored on your server (and on-device for the mobile apps) and play back without streaming. ![The PinePods downloads page](/img/screenshots/downloadspage.png) ## Downloading episodes Download an individual episode from its options menu on any client. Want it to happen automatically for a whole show? See [Auto-Download](./AutoDownload.md). ## The downloads page The **Downloads** page is your hub for everything you've saved offline: - Browse all of your downloaded episodes in one place. - Play, queue, or remove downloads. - See download progress for items still in flight. On mobile, the downloads experience includes a **download dashboard** and a dedicated **download activity** view with live progress tracking, so you can watch large downloads complete. ## Performance Downloads run **asynchronously in the background** — kicking off a large download won't freeze the rest of the app. PinePods also sends proper `Accept` and `User-Agent` headers when fetching episodes, which prevents some podcast hosts from blocking the download. ## Storage On the server, downloads are written to the `/opt/pinepods/downloads` directory, which you mount as a volume in your Docker Compose file. Point it at wherever you want the files to live on your host: ```yaml volumes: - /home/user/pinepods/downloads:/opt/pinepods/downloads ``` ## Tips - Set the `PUID`/`PGID` environment variables to your host user so downloaded files stay readable on the host system. - Combine downloads with [Auto-Download](./AutoDownload.md) and a "Fresh Releases" [smart playlist](./smart-playlists.md) for a fully hands-off offline setup. --- ## Favorites & Favorite Categories Favorites give you a fast way to spotlight the podcasts and categories you reach for most. ## Podcast favorites Mark any podcast as a **favorite** to surface it quickly. You can toggle favorite status from the podcast's detail page, and your favorites are easy to get back to from the sidebar / app drawer. - Favoriting doesn't change your subscriptions or what shows up in your feed — it's purely a way to pin your most-loved shows for quick access. - Favorite status is part of your account, so it syncs across every device you sign in on. ## Favorite categories Beyond individual podcasts, you can highlight **favorite categories** — the genres or topics you care about most — so they're front and center when you're browsing. ## Where favorites show up - In the **sidebar / app drawer** for one-tap access. - On the **podcast detail page**, where you toggle the favorite star. - In your **user stats**, which can reflect your favorite podcasts and categories. ## Tips - Use favorites for shows you listen to every week, and lean on [smart playlists](./smart-playlists.md) for automatic, rule-based collections. --- ## Funding Pinepods supports Funding as defined by the PodcastIndex Namespace. Any podcast supports this tag will show the funding link on the podcast page for that particular podcast in the form of a monetary icon as seen below: ![Funding Button](/img/funding.png) --- ## Local Podcasts & Local Media PinePods can add podcasts from **local files on your server** — audiobooks, archived shows, recordings, or any audio you keep on disk — alongside the podcasts you subscribe to over RSS. ![Adding a local podcast in PinePods](/img/screenshots/localpodcast.png) ## Mounting your media PinePods reads local media from a directory inside the container at `/opt/pinepods/local-media`. Mount your library there in your Docker Compose file: ```yaml services: pinepods: image: madeofpendletonwool/pinepods:latest volumes: - /home/user/pinepods/downloads:/opt/pinepods/downloads - /home/user/pinepods/backups:/opt/pinepods/backups # Mount your local audio library - /home/user/Media/podcasts:/opt/pinepods/local-media ``` ## Adding a local podcast From the **Local Podcast** settings, browse the mounted directory and add a folder as a podcast. PinePods will: - **Detect audio files** in the directory and turn them into episodes. - **Find cover art** in the folder (or let you set artwork) for the podcast image. - **Read metadata** (such as ID3 tags) to fill in episode titles and details. ## Refreshing Dropped new files into the folder? Use the **refresh local podcast** action to rescan the directory and pick up new episodes — the same way an RSS podcast refreshes for new entries. ## Tips - Local podcasts behave like any other podcast: queue them, add them to playlists, track progress, and play them on any client. - Keep each "show" in its own subfolder so cover art and metadata stay grouped correctly. --- ## People Pinepods supports the Person tag as defined by the PodcastIndex Namespace in addition to the PodPeopleDB. Any podcast that either includes the Person tag or is associated with a host in the PodPeopleDB will show hosts on the main podcast page in a dropdown: ![People Podcast;](/img/people.png) In addition, you'll find individual episodes show guests as part of the people shown on the episode view: ![Guest Podcast;](/img/peopleepisode.png) The PodPeople DB is used in addition to the Person tag to suppliment podcasts that don't yet support the tag. PodPeopleDB is a community contribution and any podcasts that don't have hosts associated with them or a person tag will give an option to add hosts manually. Which looks like this: ![People Empty Podcast;](/img/peopleempty.png) If you do see a podcast that looks like this and are willing to help out please click the link and add information on the hosts that are part of your favorite podcasts! This will allow you to subscribe to feeds from your favorite hosts and will allow anyone else in the future to get the host data as well! --- ## The Queue The queue is your up-next list. Add episodes to it from anywhere, reorder them, and PinePods plays through them one after another. ![The PinePods queue side panel](/img/screenshots/queuepage.png) ## The queue side panel (web) On the web client, the queue lives in a **persistent side panel** you can open from any page — you don't have to navigate away from what you're doing to see or change what's playing next. From the panel (and from episode context menus) you can: - **Add** episodes to the queue. - **Reorder** episodes by dragging them into the order you want. - **Remove** an episode with the "Remove From Queue" action. - **Clear** the queue when you want to start fresh. - **Multi-select** episodes with checkboxes to manage several at once. ## Auto-play next When the current episode finishes, the **next episode in the queue starts automatically**, giving you a continuous listening session. This works hand-in-hand with: - [Serial podcasts](./SerialPodcasts.md), which advance a single show in order. - Playlist continued play, which plays a playlist straight through. ## On mobile The mobile apps include the same queue concept with auto-play-next when an episode finishes, plus inline queue controls on the podcast detail screen. ## Tips - Build a listening session by queueing a few episodes across different shows, then let auto-play carry you through them. - Use the multi-select checkboxes to quickly clear out episodes you've changed your mind about. --- ## Searching Pinepods supports both The Podcast Index as well as iTunes search. Utilizing The Podcast Index is highly recommended as it supports many more modern features for Podcasts that Pinepods supports such as chapters, people tags, funding tags, and transcripts! When searching for a new podcast you can choose which index you search. It defaults to The Podcast Index: ![Seach Button](/img/search.png) --- ## Serial Podcasts & Auto-Play Some podcasts are meant to be listened to **in order** — narrative shows, audio dramas, or course-style series. PinePods lets you mark a podcast as **serial** so episodes advance from oldest to newest automatically as you listen. ## Marking a podcast as serial Open the podcast and enable the **serial** option in its settings. Once set: - Playback advances through the show **in chronological order** (oldest unplayed first) rather than newest-first. - When the current episode finishes, the next episode in the series begins automatically. ## Auto-play across the queue and playlists Serial mode is part of a broader set of auto-advance behaviors in PinePods: - **Queue auto-play** — when an episode in your queue finishes, the next queued episode starts automatically. - **Playlist continued play** — playlists (including smart playlists) play through their episodes one after another, so a playlist behaves like a continuous listening session. ## Tips - Combine serial mode with [Auto-Download](./AutoDownload.md) so each new installment is downloaded and ready before you reach it. - For non-narrative shows you'd rather hear newest-first, simply leave serial mode off — it's opt-in per podcast. --- ## Shared Episode Links Shared episode links let you generate a **shareable URL for a single episode** so you can send it to a friend — even if they don't have an account on your server. ![Managing shared episode links in PinePods](/img/screenshots/sharedlinks.png) ## Creating a shared link You can create a shared link for an episode from its options, and manage all of your links from the **Shared Links** section in Settings. When someone opens a shared link, they land on a dedicated shared-episode page that displays the episode details and lets them play it. ## Managing your links The Shared Links settings page gives you full control over every link you've created: - **List** all of your currently active shared links. - **Delete** a link to revoke access immediately. - **Extend** a link's expiration when you need it to stay live longer. ## Expiration Shared links can carry an **expiration**, so a link you send today won't stay open forever. You can extend or delete links at any time from the Shared Links page. ## Tips - Because the link resolves to a self-contained page, recipients don't need to log in or install anything to listen. - Revoke links you no longer need with **Delete** rather than letting them sit — it keeps your shared list tidy and your content private. --- ## Listening Statistics PinePods keeps track of how you listen and surfaces it on your **User Stats** page — a personal dashboard of your podcast habits. ![The PinePods user statistics dashboard](/img/screenshots/userstats.png) ## What you'll see The stats page brings together metrics and charts about your listening, which can include things like: - Total time spent listening. - Episodes started and completed. - Your most-listened podcasts and favorite categories. - Activity over time, visualized as charts. ## Per-user Stats are tracked **per user**, so everyone on your server sees their own numbers. Your listening data stays on your own server — like everything else in PinePods, it's never sent anywhere else. ## Tips - Stats build up over time as you listen, so the page gets richer the longer you use PinePods. - Use the page to spot shows you've drifted away from — then mark the ones you love as [favorites](./Favorites.md) to keep them close. --- ## Transcripts Pinepods supports Transcripts as defined by the PodcastIndex Namespace. Any podcast episode that you play that supports this field will automatically show links to the episode transcript in the episode view as seen below: ![Chapters Button](/img/transcript.png) ## AI-generated transcripts Even when a podcast doesn't publish its own transcript, Pinepods can **generate one with AI** using the optional AI container — complete with a timecoded, clickable view. It's also the foundation for [AI ad detection](../AI/AdDetection.md). See **[AI Transcription](../AI/Transcription.md)** for how to set it up and use it. --- ## Video Podcasts PinePods plays **video podcasts**, not just audio. When a feed publishes video enclosures, PinePods detects the media type and renders episodes in a proper video player instead of the audio player. ![PinePods video player](/img/screenshots/videoplayer.png) ## How it works - **Automatic detection** — when you subscribe to a feed (or refresh one), PinePods inspects each episode's enclosure and records whether it's audio or video. No setup is required; video episodes are flagged automatically. - **Video player** — playing a video episode opens an embedded video player on the episode page, sized to the content, with the usual playback controls, speed, and position tracking. - **YouTube** — channels you subscribe to through search are treated as video sources and play through the same video pipeline. ## On mobile The mobile apps handle both audio and video streams through their native media layers (Media3/ExoPlayer on Android, the native player on iOS), so video episodes play back with the same background and lock-screen behavior as audio. ## Tips - Listening progress and "played" state work the same for video as for audio, so a video episode you partially watch will show up in **Currently Listening** smart playlists just like audio. - Downloads work for video episodes too — download for offline viewing the same way you would an audio episode. --- ## Pinepods GPodder API Sync Guide ## Introduction Pinepods offers powerful podcast synchronization capabilities through the GPodder API, allowing you to keep your podcast subscriptions in sync across multiple devices and applications. This guide explains the different sync options available, how to set them up, and tips for getting the most out of podcast synchronization. ## Sync Options Overview Pinepods offers three different methods for podcast synchronization: 1. **Internal GPodder API** (Recommended) - Uses Pinepods' built-in GPodder API server 2. **External GPodder-compatible Server** - Connects to an external GPodder API server 3. **Nextcloud Sync** - Connects to a Nextcloud instance with the GPodder integration Each option has its own advantages and use cases, which are detailed below. ## Internal GPodder API (Recommended) The internal GPodder API is the recommended option for most users. It provides a seamless experience without requiring any external services and allows you to sign into apps other than Pinepods to sync from directly using your Pinepods account and Pinepods url! ### Advantages - No external dependencies or services needed - Fast and reliable synchronization - The Gpodder API is built in Go for speed - Fully integrated with Pinepods - Compatible with any GPodder client (including AntennaPod, gPodder, and other apps) - All features implemented from the Gpodder API spec - Automatic device management ### Setting Up Internal GPodder API 1. Go to **Settings** > **Podcast Sync** 2. In the **Internal GPodder API** section, toggle the switch to **Enabled** 3. The synchronization is now active, and you'll see "Internal GPodder API enabled" as your current sync server ### Connecting Clients to Internal GPodder API When setting up your podcast app to sync with Pinepods' internal GPodder API: 1. Use the following server URL: `https://[your-pinepods-server]` 2. Simply use your Pinepods username and password to sign in ### Advanced Options Once you've enabled the internal GPodder API, you can access advanced options: 1. Click on the **Show Extra Options** button that appears below the sync section 2. Here you can: - View and manage all your connected devices - Create new devices - Set a default device for synchronization - Manually sync from or push to GPodder - See the sync status of each device ### Managing Devices #### Creating a New Device 1. In the advanced options, find the **Add New Device** section 2. Enter a device name (required) 3. Select a device type (desktop, laptop, mobile, server, or other) 4. Optionally add a caption to identify the device more easily 5. Click **Add Device** #### Setting a Default Device 1. Select a device from the dropdown menu 2. Click the **Set as default** button 3. The default device will be automatically selected for background sync operations #### Syncing with a Device 1. Select a device from the dropdown menu 2. Click **Sync from GPodder** to pull changes from that device 3. Click **Push to GPodder** to push your current Pinepods subscriptions to that device #### Syncing from a different device So for example AntennaPods created a specific AntennaPods device and you want to use a different one in Pinepods. You can then sync **from** the Antennapods device **into** your Pinepods device. Follow these steps: 1. Ensure the device you want to sync **into** is your default 2. Change the devices dropdown to the device you want to sync **from** 3. Click the Sync button Everything from your previous device will sync into the new one. ## External GPodder-compatible Server If you already have a GPodder server setup, you can connect Pinepods to it. ### Advantages - Works with existing GPodder infrastructure - Allows synchronization with other applications already using your GPodder server - Good for integrating Pinepods into an existing podcast ecosystem ### Setting Up External GPodder Sync 1. Ensure the **Internal GPodder API** is disabled (toggle switch set to off) 2. In the **GPodder-compatible Server** section, enter: - Server URL (e.g., `https://mygpodder.example.com`) - Username - Password 3. Click **Test Connection** to verify your credentials 4. Click **Authenticate** to complete the setup All the Advanced Option documentation above applies here as well. ## Nextcloud Sync For Nextcloud users, Pinepods supports synchronization through Nextcloud's GPodder integration. Note that there are some limitations with Nextcloud sync as it doesn't fully support all Gpodder APIs. Such as devices. I don't recommend Nextcloud sync but if you already have a Nextcloud server and just want to sync podcasts between devices it'll work. ### Advantages - Integration with your existing Nextcloud environment - Works well if you're already using Nextcloud for other services - Simple authentication flow ### Setting Up Nextcloud Sync 1. Ensure the **Internal GPodder API** is disabled (toggle switch set to off) 2. In the **Nextcloud Sync** section, enter your Nextcloud server URL 3. Click **Authenticate** 4. A new browser tab will open to authenticate with your Nextcloud instance 5. Follow the prompts to authorize Pinepods 6. Return to Pinepods, which will display "Nextcloud server has been authenticated successfully" when complete ## Troubleshooting and Tips ### Compatibility Notes Gpodder sync apps that I know work: - Pinepods' Gpodder API - Nextcloud Sync - Podfetch - oPodsync (There's some limitations in opodsync once the DB gets too big. Not recommended.) ### Reporting Issues If you encounter problems with specific GPodder servers or clients: 1. Test with the internal GPodder API first to isolate the issue 2. Check if the issue persists with different clients 3. Open an issue on the [Pinepods GitHub repository](https://github.com/madeofpendletonwool/PinePods/issues) with: - The sync method you're using - The client application and version - Server details (if using external sync) - Steps to reproduce the issue - Error messages or logs if available ## Frequently Asked Questions **Q: Which sync option should I choose?** A: For most users, the internal GPodder API is recommended for its simplicity and reliability. Use external options only if you have specific requirements or existing infrastructure. **Q: Can I switch between sync methods?** A: Yes, but you'll need to disable the current method before enabling another. Your podcast subscriptions will remain intact as they will just sync into the new one. **Q: How often does synchronization happen?** A: Pinepods syncs automatically every 15 mins, but you can also trigger manual syncs through the advanced options. **Q: Will enabling sync affect my existing podcasts?** A: No, enabling sync will not modify your existing podcast subscriptions. It will only start tracking changes from that point forward. **Q: Do I need to create a device manually?** A: For the internal GPodder API, Pinepods will create a default device automatically. You only need to create additional devices if you want to manage sync more granularly. **Q: Can I use multiple sync methods simultaneously?** A: No, only one sync method can be active at a time. --- ## PinePods Smart Playlist Creation Options This document explains all the available options when creating smart playlists in PinePods and how each option affects the resulting playlist content. ## Overview Smart playlists in PinePods are dynamic collections of episodes that are automatically populated based on a set of criteria you define. The playlist content is updated periodically to match your criteria, ensuring fresh and relevant episodes are always available. ![Creating a smart playlist in PinePods](/img/screenshots/playlistcreator.png) ## Basic Information ### Name (Required) - **Purpose**: The display name for your playlist - **Effect**: This is how your playlist will appear in the interface - **Requirements**: Must be unique among your playlists ### Description (Optional) - **Purpose**: A brief description of what the playlist contains - **Effect**: Provides context about the playlist's purpose - **Display**: Shown in the playlist card and details view ### Icon - **Purpose**: Visual representation of your playlist - **Options**: Choose from 300+ Phosphor icons (music, broadcast, star, etc.) - **Default**: `ph-playlist` - **Effect**: Displayed alongside the playlist name ## Episode Filtering Options ### Filter by Podcasts (Optional) - **Purpose**: Limit episodes to specific podcasts in your collection - **Options**: - None selected = Include episodes from ALL podcasts - Select specific podcasts = Only include episodes from those podcasts - **Effect**: Acts as a primary filter - only episodes from selected podcasts will be considered for other criteria ### Episode State Filters #### Include Unplayed - **Default**: `true` (enabled) - **Purpose**: Include episodes you haven't started listening to - **Criteria**: Episodes with no listening history OR listen duration = 0 - **Effect**: Adds fresh, new episodes to your playlist #### Include Partially Played - **Default**: `true` (enabled) - **Purpose**: Include episodes you've started but not finished - **Criteria**: Episodes with listen duration > 0 AND not marked as completed - **Effect**: Brings back episodes you're in the middle of - **Note**: Required for Play Progress Range filters to work #### Include Played - **Default**: `false` (disabled) - **Purpose**: Include episodes you've already completed - **Criteria**: Episodes marked as completed (listen duration >= total duration) - **Effect**: Can create "favorites" or "replay" type playlists ## Duration Filters ### Duration Range (Minutes) - **Min Duration**: Only include episodes longer than X minutes - **Max Duration**: Only include episodes shorter than X minutes - **Effect**: - Setting Min=30 excludes short clips and trailers - Setting Max=60 excludes very long episodes - Use both to target specific episode lengths (e.g., 20-45 minutes for commute listening) ### Play Progress Range (%) - **Only Active When**: "Include Partially Played" is enabled - **Min %**: Only include episodes you've listened to at least X% of - **Max %**: Only include episodes you've listened to no more than X% of - **Examples**: - Min=5%, Max=95% = Episodes you've started but not finished - Min=75% = Episodes you're almost done with ("Almost Done" playlist) - Max=25% = Episodes you've barely started ## Time-Based Filtering ### Time Filter (Hours) - **Purpose**: Only include episodes published within the last X hours - **Effect**: Creates "Fresh Releases" type playlists - **Examples**: - 24 hours = Today's episodes only - 168 hours (7 days) = This week's episodes - Leave empty = No time restriction ## Sorting and Organization ### Sort Order Determines the order episodes appear in your playlist: #### By Date - **Newest First** (`date_desc`): Latest episodes at the top - **Oldest First** (`date_asc`): Earliest episodes at the top #### By Duration - **Longest First** (`duration_desc`): Longest episodes at the top - **Shortest First** (`duration_asc`): Shortest episodes at the top ### Group by Podcast - **Default**: `false` (disabled) - **When Enabled**: Episodes are grouped by their podcast, then sorted within each podcast group - **Effect**: Prevents one very active podcast from dominating your playlist - **Use Case**: Ensures variety when you follow podcasts with different posting frequencies ### Max Episodes - **Purpose**: Limits the total number of episodes in the playlist - **Behavior**: After applying ALL other filters and sorting, only the first X episodes are included - **Examples**: - Sort by "Longest First" + Max Episodes = 50 → Gets the 50 longest episodes that match your criteria - Sort by "Newest First" + Max Episodes = 100 → Gets the 100 most recent episodes that match your criteria - **Important**: This is applied AFTER sorting, so you get the "best" X episodes according to your sort criteria ## How Filtering Works (Order of Operations) 1. **Podcast Filter**: Start with episodes from selected podcasts (or all if none selected) 2. **Time Filter**: Remove episodes outside the time window (if specified) 3. **Duration Filter**: Remove episodes outside duration range (if specified) 4. **Episode State Filter**: Include only episodes matching your play state criteria 5. **Play Progress Filter**: Further filter partially played episodes by progress percentage 6. **Sorting**: Order the remaining episodes according to sort criteria 7. **Grouping**: If enabled, group episodes by podcast while maintaining sort order within groups 8. **Max Episodes**: Take only the first X episodes from the sorted/grouped list ## Example Playlist Scenarios ### "Commute Ready" Playlist - **Duration**: 20-45 minutes - **Include**: Unplayed + Partially Played (5-90%) - **Sort**: Newest First - **Max Episodes**: 20 - **Result**: Recent episodes of good commute length, excluding barely-started and almost-finished episodes ### "Catch Up on Long Episodes" Playlist - **Duration**: 60+ minutes - **Include**: Unplayed only - **Sort**: Oldest First - **Group by Podcast**: Enabled - **Max Episodes**: 15 - **Result**: Oldest unplayed long-form episodes, distributed across podcasts ### "Almost Done" Playlist - **Include**: Partially Played only - **Play Progress**: 75-95% - **Sort**: Longest First - **Max Episodes**: 10 - **Result**: Episodes you're nearly finished with, prioritizing longer content ### "Fresh Discoveries" Playlist - **Time Filter**: 168 hours (1 week) - **Include**: Unplayed only - **Duration**: 15-60 minutes - **Sort**: Newest First - **Group by Podcast**: Enabled - **Max Episodes**: 50 - **Result**: This week's new episodes of reasonable length, with variety across podcasts ## Tips for Effective Playlists 1. **Start Simple**: Begin with basic filters and add complexity as needed 2. **Use Max Episodes**: Prevents overwhelming playlists and improves performance. It will select the most relevant episodes to what you select first. For example, if you set filtering to longest first, it will pick the longest ones first for the playlist. 3. **Group by Podcast**: Essential when following many active podcasts 4. **Combine State Filters**: Mix unplayed and partially played for variety 5. **Time + Duration**: Combine for targeted content (e.g., "This week's short episodes") 6. **Progress Ranges**: Fine-tune partially played content to match your preferences ## System Playlists PinePods includes seven built-in system playlists that demonstrate advanced filtering and provide ready-to-use collections: - **Fresh Releases**: Latest episodes from the last 24 hours using time filtering - **Currently Listening**: Episodes you've started but haven't finished using progress filtering - **Almost Done**: Episodes you're close to finishing (75%+ complete) using high progress thresholds - **Quick Listens**: Short episodes under 15 minutes, perfect for quick breaks using duration filtering - **Commuter Mix**: Episodes between 20-40 minutes, ideal for average commute times using duration range - **Longform**: Extended episodes over 1 hour, ideal for long drives or deep dives using minimum duration - **Weekend Marathon**: Longer episodes (30+ minutes) perfect for weekend listening using duration filtering These system playlists cannot be deleted but serve as examples of effective playlist configurations and provide immediate value for different listening scenarios. ![The Commuter Mix smart playlist populated with episodes](/img/screenshots/playlistpage.png) --- ## Firewood Episode Beaming Guide Complete guide to Firewood's remote control and episode beaming functionality - send episodes from any device to your Firewood players across your network. ## What is Episode Beaming? Episode beaming is Firewood's signature feature that allows you to remotely control Firewood players from other devices on your network. Think of it as "casting" or "AirPlay" for podcast episodes - you can send episodes from a web browser, mobile app, or any device to play on your Firewood terminal players. ### Key Features - **Network Discovery**: Automatically finds Firewood players on your local network - **Episode Streaming**: Send episodes directly to remote Firewood players - **Remote Control**: Full playback control (play, pause, skip, volume) from any device - **Multi-Player Support**: Control multiple Firewood instances simultaneously - **Progress Sync**: Playback position syncs with your PinePods server - **Resume Capability**: Start episodes at specific positions (resume functionality) ## How It Works ### Architecture Overview 1. **Firewood Player** runs on your computer/server with audio output 2. **Remote Control Server** built into each Firewood instance 3. **mDNS Discovery** automatically advertises players on network 4. **HTTP API** provides remote control interface 5. **Web Integration** (future) will add "beam to Firewood" buttons ### Network Discovery (mDNS) Firewood automatically advertises itself on your local network using mDNS (Multicast DNS): - **Service Type**: `_pinepods-remote._tcp.local.` - **Instance Name**: `Firewood-{8-char-UUID}` (e.g., `Firewood-47A053CD`) - **Port**: Automatically allocated (starts at 8042, finds available port) - **Metadata**: Includes Firewood version and connected PinePods server ### Port Management Firewood uses intelligent port allocation: - **Default Port**: 8042 - **Fallback Sequence**: 8043, 8044, 8080-8083, 3000-3002, 4000-4002, 9000-9002 - **Final Fallback**: OS-assigned random port - **Discovery**: Always use mDNS-discovered port, never assume port number ## Remote Control API Firewood exposes a REST API for complete remote control functionality. ### Base URL Format ``` http://{firewood_ip}:{discovered_port} ``` ### API Endpoints #### Player Information ```bash GET / ``` Returns basic player information: ```json { "success": true, "data": { "name": "Firewood-47A053CD", "version": "0.1.0", "server_url": "http://your-pinepods-server:8032", "user_id": 1 } } ``` #### Playback Status ```bash GET /status ``` Returns current playback state: ```json { "success": true, "data": { "is_playing": true, "current_episode": { "episode_id": 123, "episode_title": "Episode Title", "podcast_name": "Podcast Name", "episode_artwork": "http://artwork.url", "duration": 3600 }, "position": 1234, "duration": 3600, "volume": 0.7 } } ``` #### Episode Beaming ```bash POST /play ``` Send an episode to play: ```json { "episode_id": 123, // Optional - for tracking "episode_url": "http://audio.url", // Required - direct audio URL "episode_title": "Episode Title", // Required "podcast_name": "Podcast Name", // Required "episode_duration": 3600, // Required - seconds "episode_artwork": "http://art.url", // Optional "start_position": 120 // Optional - resume position in seconds } ``` #### Playback Controls ```bash POST /pause # Pause playback POST /resume # Resume playback POST /stop # Stop playback ``` #### Skip Control ```bash POST /skip ``` ```json { "seconds": 15 // Positive = forward, negative = backward } ``` #### Volume Control ```bash POST /volume ``` ```json { "volume": 0.7 // 0.0 to 1.0 } ``` #### Seek Control ```bash POST /seek ``` ```json { "position": 300 // Seek to position in seconds } ``` ## Using the Test Script Firewood includes a comprehensive Python test script for discovery and remote control. ### Setup ```bash # Create virtual environment python3 -m venv venv source venv/bin/activate # Install dependencies pip install -r requirements.txt ``` ### Discovery ```bash # Discover all Firewood players on network python test_remote_control.py --discover # Get JSON output for programmatic use python test_remote_control.py --discover --json ``` ### Remote Control ```bash # Interactive control session python test_remote_control.py -u http://192.168.1.100:8042 --interactive # Direct episode beaming python test_remote_control.py -u http://192.168.1.100:8042 --beam-url http://audio.mp3 # Status check only python test_remote_control.py -u http://192.168.1.100:8042 ``` ### Interactive Commands When in interactive mode, use these commands: - `s` - Show current playback status - `p` - Toggle play/pause - `stop` - Stop playback - `+15` - Skip forward 15 seconds - `-15` - Skip backward 15 seconds - `vol 75` - Set volume to 75% - `seek 300` - Seek to 5 minutes (300 seconds) - `beam [URL]` - Beam audio file directly to player - `play` - Play test episode - `q` - Quit interactive mode ## Manual Testing with cURL ### Discovery Test ```bash # Test if Firewood is responding curl http://192.168.1.100:8042/ # Check current status curl http://192.168.1.100:8042/status ``` ### Episode Beaming Test ```bash curl -X POST http://192.168.1.100:8042/play \ -H "Content-Type: application/json" \ -d '{ "episode_url": "http://example.com/episode.mp3", "episode_title": "Test Episode", "podcast_name": "Test Podcast", "episode_duration": 1800, "start_position": 0 }' ``` ### Control Tests ```bash # Pause curl -X POST http://192.168.1.100:8042/pause # Skip forward 30 seconds curl -X POST http://192.168.1.100:8042/skip \ -H "Content-Type: application/json" \ -d '{"seconds": 30}' # Set volume to 50% curl -X POST http://192.168.1.100:8042/volume \ -H "Content-Type: application/json" \ -d '{"volume": 0.5}' ``` ## Configuration ### Environment Variables ```bash # Custom port (if not using auto-discovery) export FIREWOOD_REMOTE_PORT=8080 # Disable remote control entirely export FIREWOOD_REMOTE_DISABLED=true # Run Firewood pinepods_firewood ``` ### Network Requirements - **Same Network**: All devices must be on the same local network - **mDNS Support**: Network must allow multicast traffic (most home networks do) - **Firewall**: Allow incoming connections on Firewood ports - **No VPN Interference**: Some VPNs block local network discovery ## Security Considerations ### Local Network Only - Beaming only works on local networks (LAN/WiFi) - mDNS doesn't traverse internet or VPN boundaries - No external access possible by design ### No Authentication - Intended for trusted home/office networks - Any device on network can control Firewood players - Consider network segmentation for sensitive environments ### CORS Support - Firewood includes CORS headers for web browser requests - Enables future web UI integration - Allows JavaScript-based remote control apps ## Troubleshooting ### Discovery Issues **No Players Found:** - Verify Firewood is running and remote control is enabled - Check devices are on same network/subnet - Test with direct IP connection: `python test_remote_control.py -u http://IP:8042` - Check firewall settings (allow port 5353 for mDNS) **Players Disappear:** - Normal when Firewood exits (services auto-unregister) - Network changes can cause temporary disappearance - Re-run discovery after network changes ### Connection Issues **Connection Refused:** - Firewood not running on target device - Wrong IP address or port - Firewall blocking connection - Try different ports: 8042, 8043, 8044 **Timeout Errors:** - Network congestion or slow connection - Player busy processing previous request - Increase timeout in test script **JSON Parse Errors:** - Incompatible Firewood version - Network corruption (rare) - Try direct cURL test to isolate issue ### Audio Issues **Episode Won't Play:** - Invalid audio URL - Audio format not supported - Network can't reach audio file - Check Firewood logs for detailed error **Playback Stops Unexpectedly:** - Network interruption to audio source - Firewood crashed (check logs) - Audio device issues on Firewood host ## Platform Support ### Firewood Remote Control Server - **Linux**: Full support - **macOS Intel**: Full support - **macOS Apple Silicon**: Currently disabled due to audio library limitations - **Windows**: Full support (planned) ### Remote Control Clients - **Any Platform**: Python test script works everywhere - **Web Browsers**: Ready for integration (CORS enabled) - **Mobile Apps**: Can use HTTP API directly - **IoT/Smart Home**: Standard HTTP/JSON integration ## Advanced Features ### Accurate Duration Parsing Firewood automatically parses accurate episode durations: 1. **HTTP Headers**: Checks for `x-content-duration` header 2. **File Analysis**: Downloads and analyzes audio with Symphonia 3. **Fallback**: Conservative bitrate estimation This ensures accurate progress tracking and seeking, especially for dynamically-inserted ads. ### Multi-Instance Support Run multiple Firewood players simultaneously: - Each gets unique mDNS service name - Automatic port allocation prevents conflicts - Control each player independently - Perfect for multi-room audio setups ### Resume Functionality Episodes can start at specific positions: ```json { "episode_url": "http://audio.mp3", "episode_title": "Episode Title", "podcast_name": "Podcast Name", "episode_duration": 3600, "start_position": 1800 // Resume at 30 minutes } ``` ## Future Web Integration When implemented in PinePods web UI, you'll have: ### Discovery Integration - Automatic network scanning for Firewood players - Player status display in web interface - Connection health monitoring ### Episode Beaming UI - "Play on Firewood" buttons on episode pages - Player selection dropdown/modal - One-click episode sending ### Remote Control Interface - Mini player widget when episode is beaming - Real-time progress sync - Volume slider and skip controls - Multi-room control panel ### Smart Features - Resume position sync between web and Firewood - Automatic player selection (last used, same room, etc.) - Queue management across devices ## Best Practices ### Network Setup - Use reliable WiFi for best experience - Consider dedicated IoT/media network for multiple players - Ensure good signal strength to Firewood devices ### Player Management - Use descriptive hostnames for Firewood devices - Monitor player health with periodic status checks - Restart players if they become unresponsive ### Development Integration - Always use mDNS discovery, never hardcode IPs/ports - Handle network errors gracefully - Implement retry logic for transient failures - Cache discovered players but refresh regularly --- **Ready to start beaming?** Episode beaming transforms Firewood from a local terminal player into a network-connected audio system that can be controlled from any device. Perfect for home automation, multi-room audio, and seamless podcast listening across your devices! --- ## Firewood Setup and Login Guide A comprehensive guide to getting started with PinePods Firewood - your terminal-based podcast client. ## Prerequisites **PinePods Server Required**: Firewood is a client application that connects to a PinePods server. You'll need a running PinePods server to use Firewood. ### Setting Up PinePods Server If you don't have a PinePods server yet, visit **[pinepods.online](https://pinepods.online)** for complete installation instructions. **Note**: Make sure your PinePods server is accessible from the device where you'll run Firewood. ## Installing Firewood ### Quick Install (Recommended) **One-liner installer** for Linux/macOS/Windows: ```bash curl -sSL https://raw.githubusercontent.com/madeofpendletonwool/pinepods-firewood/main/install.sh | bash ``` ### Alternative Installation Methods **Package Managers:** ```bash # Homebrew (macOS/Linux) brew install pinepods-firewood # Cargo (Rust) cargo install pinepods-firewood # Arch Linux (AUR) yay -S pinepods-firewood ``` **Manual Download:** - Download pre-built binaries from [GitHub Releases](https://github.com/madeofpendletonwool/pinepods-firewood/releases/latest) - Extract and place in your PATH ## First Launch Setup ### 1. Start Firewood ```bash pinepods_firewood ``` ### 2. Server Configuration When you first launch Firewood, you'll be prompted to configure your connection: **Server URL**: Enter your PinePods server URL - Include the protocol: `http://` or `https://` - Examples: - `https://mypinepods.com` - `http://192.168.1.100:8080` - `http://localhost:8032` **Port**: If your server runs on a non-standard port, include it in the URL. ### 3. Authentication **Username and Password**: Enter your PinePods account credentials - These are the same credentials you use for the PinePods web interface - Credentials are securely stored locally for future sessions **Multi-Factor Authentication (MFA)**: If enabled on your account: - Enter your MFA code when prompted - Firewood supports TOTP-based MFA (Google Authenticator, Authy, etc.) ### 4. Timezone Selection **Choose Your Timezone**: Select your local timezone for accurate episode timestamps - Use arrow keys to navigate the timezone list - Press Enter to confirm your selection - This affects how episode publication dates and times are displayed ### 5. Session Persistence Firewood automatically saves your login session: - **Automatic Login**: Future launches will skip the login process - **Secure Storage**: Credentials are encrypted and stored locally - **Session Refresh**: Tokens are automatically refreshed as needed ## Login Process ### Standard Login Flow 1. **Launch**: Run `pinepods_firewood` 2. **Server URL**: Enter your PinePods server address 3. **Credentials**: Provide username and password 4. **MFA** (if enabled): Enter your authentication code 5. **Timezone**: Select your preferred timezone 6. **Success**: You'll be taken to the Home screen ### Session Management **Automatic Login**: If you have a saved session: - Firewood will attempt to use stored credentials - If successful, you'll go straight to the main interface - If expired, you'll be prompted to log in again **Manual Logout**: To clear stored credentials: - Navigate to Settings (when implemented) - Or delete the config file: `~/.config/pinepods-firewood/` ### Troubleshooting Login Issues **Connection Failed:** - Verify server URL is correct and accessible - Check if server is running and reachable - Ensure no firewall is blocking the connection **Authentication Failed:** - Double-check username and password - Verify MFA code is correct and not expired - Ensure your account is active on the PinePods server **Session Expired:** - Simply re-enter your credentials - Check if your account permissions have changed - Restart Firewood if issues persist **Network Issues:** - Test server connectivity: `curl http://your-server-url/api/health` - Check DNS resolution - Verify SSL certificates (for HTTPS connections) ## Security Notes **Local Storage**: - Credentials are encrypted using system keychain/credential store - Config files are stored in: `~/.config/pinepods-firewood/` - No passwords are stored in plain text **Network Security**: - Use HTTPS when possible for encrypted communication - Firewood respects server SSL certificates - MFA provides additional account protection **Permissions**: - Firewood only requires network access for server communication - No elevated system permissions needed - Audio permissions for playback functionality ## Next Steps Once logged in successfully: 1. **Explore the Interface**: Navigate using Tab or number keys (1-9) 2. **Browse Podcasts**: Check your subscriptions in the Podcasts tab 3. **Recent Episodes**: View latest content in the Episodes tab 4. **Start Listening**: Select an episode and press Enter to play ## Quick Reference **Navigation:** - `Tab` - Switch between tabs - `1-9` - Jump to specific tabs by number - `Ctrl+R` - Refresh current page - `q` - Quit application - `Ctrl+C` - Force quit **Help:** - Run `pinepods_firewood --help` for command-line options - Check [GitHub Issues](https://github.com/madeofpendletonwool/pinepods-firewood/issues) for support --- **Ready to start listening?** Follow this guide to get connected to your PinePods server and begin enjoying your podcasts from the terminal! --- ## Firewood User Guide Complete guide to using PinePods Firewood - your feature-rich terminal podcast client. ## Interface Overview Firewood provides a tabbed interface with multiple sections for managing and listening to your podcasts. Each tab offers specific functionality for different aspects of podcast management. ### Main Navigation **Tab Switching:** - `Tab` - Navigate between tabs sequentially - `1-9` - Jump directly to specific tabs by number - `Arrow Keys` / `hjkl` - Navigate within lists and content - `Enter` - Select/activate items - `q` / `Ctrl+C` - Quit application **Global Controls:** - `Space` - Global play/pause toggle (works from any tab) - `Ctrl+R` - Refresh current page/content - `Esc` - Return to previous screen or cancel actions ## Tab-by-Tab Guide ### 🏠 Home Tab (1) Your dashboard for quick access to recent content and recommendations. **Features:** - **Recent Episodes**: Latest episodes from your subscribed podcasts - **Continue Listening**: Resume episodes you've started but haven't finished - **Quick Access**: Jump to saved content and downloads - **Activity Overview**: See your listening progress and statistics **Navigation:** - Use arrow keys to browse through recent episodes - Press `Enter` to start playing an episode - Episodes show title, podcast name, and publication date ### 🎵 Player Tab (2) Full-screen audio player with comprehensive playback controls. **Player Interface:** - **Episode Information**: Title, podcast name, description - **Artwork Display**: Episode or podcast cover art - **Progress Bar**: Visual playback progress with time indicators - **Control Buttons**: Play, pause, skip forward/backward, volume **Playback Controls:** - `Space` / `Enter` - Play/pause toggle - `→` / `l` - Skip forward 15 seconds - `←` / `h` - Skip backward 15 seconds - `↑` / `k` - Increase volume - `↓` / `j` - Decrease volume - `0-9` - Seek to percentage (0% to 90%) - `m` - Mute/unmute audio **Advanced Features:** - **Progress Sync**: Automatically syncs listening progress with PinePods server - **Resume Playback**: Pick up where you left off on any device - **Smart Skip**: Respects podcast chapter markers when available - **Background Play**: Continues playing while you browse other tabs ### 📻 Episodes Tab (3) Comprehensive episode management with filtering and search capabilities. **Content Views:** - **All Episodes**: Complete feed of recent episodes from all subscriptions - **In Progress**: Episodes you've started but haven't finished - **Completed**: Episodes you've finished listening to **Features:** - **Auto-loading**: Episodes load automatically as you scroll - **Real-time Search**: Filter episodes by title or podcast name - **Status Tracking**: Visual indicators for play status and progress - **Batch Actions**: Mark multiple episodes as played/unplayed **Navigation:** - `↑/↓` - Browse episode list - `Enter` - Play selected episode - `Space` - Quick play/pause - `/` - Activate search mode - `Esc` - Clear search filter ### 🎙️ Podcasts Tab (4) Browse your podcast subscriptions with a dual-panel interface. **Layout:** - **Left Panel**: List of subscribed podcasts - **Right Panel**: Episodes from the selected podcast **Navigation:** - `Tab` - Switch between left and right panels - `↑/↓` or `j/k` - Navigate podcast list - `Enter` - Select podcast (loads episodes in right panel) - In episodes panel: `↑/↓` to browse, `Enter` to play **Features:** - View all your podcast subscriptions organized alphabetically - See episode counts and latest episode information - Quick access to specific podcast episodes - Podcast artwork and descriptions (when available) ### 📝 Queue Tab (5) Manage your episode queue and listening order. **Features:** - **Queue Management**: Add, remove, and reorder episodes - **Queue Display**: View your current listening queue - **Episode Controls**: Play episodes directly from queue - **Queue Actions**: Clear queue and manage playback order **Navigation:** - `↑/↓` - Browse queue items - `Enter` - Play selected episode - `d` / `Delete` - Remove from queue - `c` - Clear entire queue ### ⭐ Saved Tab (6) Access your bookmarked and favorite episodes. **Features:** - **Bookmarks**: Episodes you've marked for later - **Favorites**: Your starred episodes and podcasts - **Collections**: Custom groups of related episodes - **Quick Access**: Fast filtering and search within saved content - **Sync**: Saved items sync across all your devices **Navigation:** - `↑/↓` - Browse saved episodes - `Enter` - Play selected episode - `r` - Remove from saved - `/` - Search saved content ### 📥 Downloads Tab (7) Manage offline episode downloads for listening without internet. **Features:** - **Download Management**: Queue, pause, cancel downloads - **Offline Library**: Browse downloaded episodes - **Storage Monitoring**: Track disk usage and manage space - **Auto-download**: Set rules for automatic episode downloads - **Quality Settings**: Choose download quality and format **Navigation:** - `↑/↓` - Browse downloaded episodes - `Enter` - Play downloaded episode - `d` / `Delete` - Delete download - `p` - Pause/resume download ### 🔍 Search Tab (8) Discover new content and find specific episodes or podcasts. **Features:** - **Global Search**: Find episodes across all your subscriptions - **Podcast Discovery**: Browse and subscribe to new podcasts - **Advanced Filters**: Filter by date, duration, podcast, etc. - **Search History**: Quick access to previous searches - **Trending**: See popular and recommended content **Navigation:** - `/` - Enter search query - `↑/↓` - Browse search results - `Enter` - Play or subscribe to result - `Esc` - Clear search ### ⚙️ Settings Tab (9) Configure Firewood to match your preferences and setup. **Features:** - **Audio Settings**: Output device, volume levels, equalizer - **Remote Control**: Configure network settings and port - **Appearance**: Themes, colors, and layout customization - **Keyboard Shortcuts**: Customize key bindings - **Sync Settings**: Server connection and sync preferences - **Advanced Options**: Debug settings and performance tuning **Navigation:** - `↑/↓` - Browse settings categories - `Enter` - Modify setting - `Esc` - Cancel changes - `s` - Save settings ## Micro-Player Controls Firewood includes an always-visible micro-player at the bottom of every screen, providing quick access to playback controls without switching to the Player tab. **Micro-Player Features:** - **Track Info**: Current episode title and podcast name - **Playback Status**: Play/pause indicator and progress - **Quick Controls**: Play/pause, skip buttons - **Time Display**: Current position and total duration - **Volume Indicator**: Current volume level **Universal Controls:** - `Space` - Play/pause from any screen - `→` / `Ctrl+→` - Skip forward 15 seconds - `←` / `Ctrl+←` - Skip backward 15 seconds - `↑` / `Ctrl+↑` - Volume up - `↓` / `Ctrl+↓` - Volume down ## Remote Control Features Firewood can be controlled remotely from other devices on your network, making it perfect for integration with smart home systems or remote control from phones/tablets. ### Network Discovery **Automatic Discovery:** - Firewood advertises itself via mDNS as `_pinepods-remote._tcp.local.` - Other devices can automatically find and connect to your Firewood instance - No manual IP configuration needed on the same network **Manual Connection:** - Connect directly using IP:PORT (default port 8042) - Supports custom port configuration via environment variables ### Remote Control API **HTTP Endpoints:** - `GET /status` - Get current playback status - `POST /play` - Play specific episode - `POST /pause` - Pause playback - `POST /resume` - Resume playback - `POST /stop` - Stop playback - `POST /skip` - Skip forward/backward by seconds - `POST /seek` - Seek to specific position - `POST /volume` - Set volume level **Web Integration:** When implemented in PinePods web UI, you'll be able to: - "Beam" episodes directly to Firewood players - Control multiple Firewood instances from one interface - See all available players on your network - Sync playback across devices ### Remote Control Setup **Configuration:** ```bash # Custom port (default: 8042) export FIREWOOD_REMOTE_PORT=8080 # Disable remote control export FIREWOOD_REMOTE_DISABLED=true # Run Firewood pinepods_firewood ``` **Testing Remote Control:** Use the included Python test script: ```bash # Discover Firewood players python test_remote_control.py --discover # Interactive control python test_remote_control.py -u http://IP:PORT --interactive ``` ## Audio and Playback ### Supported Formats Firewood supports all major podcast audio formats: - **MP3** - Most common podcast format - **AAC/M4A** - Apple's audio format - **OGG/Vorbis** - Open source format - **FLAC** - Lossless audio format - **WAV** - Uncompressed audio ### Playback Features **Streaming:** - Direct streaming from PinePods server - No local storage required for streaming - Automatic quality adjustment based on connection **Progress Tracking:** - Syncs listening position with PinePods server - Resume playback across devices - Marks episodes as played automatically **Audio Controls:** - Variable speed playback (planned) - Sleep timer (planned) - Chapter navigation (planned) - Noise reduction (planned) ## Keyboard Shortcuts Reference ### Global Shortcuts | Key | Action | |-----|--------| | `Tab` | Switch tabs | | `1-9` | Jump to tab | | `Space` | Play/pause | | `q` | Quit | | `Ctrl+C` | Force quit | | `Ctrl+R` | Refresh | ### Navigation | Key | Action | |-----|--------| | `↑/↓` or `k/j` | Navigate up/down | | `←/→` or `h/l` | Navigate left/right | | `Enter` | Select/activate | | `Esc` | Back/cancel | ### Player Controls | Key | Action | |-----|--------| | `Space` | Play/pause | | `→` | Skip forward 15s | | `←` | Skip backward 15s | | `↑` | Volume up | | `↓` | Volume down | | `m` | Mute/unmute | | `0-9` | Seek to percentage | ### List Management | Key | Action | |-----|--------| | `/` | Search/filter | | `Esc` | Clear search | | `Page Up/Down` | Scroll pages | | `Home/End` | Go to top/bottom | ## Tips and Best Practices ### Efficient Navigation - **Use Number Keys**: Quickly jump between tabs with 1-9 - **Master the Micro-Player**: Control playback without leaving your current tab - **Search Everything**: Use `/` to quickly filter long lists - **Keyboard First**: Learn the shortcuts for faster navigation ### Managing Large Libraries - **Use Filters**: Episode tab filters help manage large subscription lists - **Save Important Episodes**: Use the Saved tab for episodes you want to return to - **Queue Management**: Build listening queues for organized podcast sessions - **Regular Cleanup**: Mark episodes as played to keep lists manageable ### Remote Control Tips - **Multiple Instances**: Run Firewood on multiple devices for whole-home audio - **Port Management**: Use custom ports if you have conflicts - **Network Setup**: Ensure devices are on same network for auto-discovery - **Firewall**: Allow mDNS (port 5353) for automatic discovery ### Performance Optimization - **Refresh Wisely**: Use `r` to refresh content when needed - **Background Updates**: Let Firewood handle automatic syncing - **Network Patience**: Allow time for episode lists to load on slower connections ## Troubleshooting ### Common Issues **Audio Not Playing:** - Check system audio settings and volume - Verify ALSA libraries are installed (Linux) - Test with different episodes to isolate the issue **Connection Problems:** - Verify PinePods server is running and accessible - Check network connectivity and firewall settings - Try manual server URL entry **Performance Issues:** - Close other resource-intensive applications - Check available system memory - Update to latest Firewood version **Remote Control Not Working:** - Ensure devices are on same network - Check if port is blocked by firewall - Try manual IP:PORT connection ### Getting Help - **GitHub Issues**: [Report bugs and request features](https://github.com/madeofpendletonwool/pinepods-firewood/issues) - **Documentation**: Check README.md and other docs in the repository - **Community**: Join discussions in GitHub Discussions - **Logs**: Enable debug logging with `RUST_LOG=debug pinepods_firewood` --- **Enjoy your podcast listening experience with Firewood!** This terminal-based client brings the power and convenience of PinePods directly to your command line, with all the features you need for managing and enjoying your favorite shows. --- ## Android Auto The PinePods Android app supports **Android Auto**, so you can listen to your podcasts from your car's display while keeping your hands on the wheel. ## Requirements - The PinePods Android app installed (from the [Google Play Store](https://play.google.com/store/apps/details?id=com.gooseberrydevelopment.pinepods), [IzzyOnDroid](https://apt.izzysoft.de/fdroid/index/apk/com.gooseberrydevelopment.pinepods), or [Obtainium](https://github.com/madeofpendletonwool/PinePods/releases)) and signed in to your server. - An Android Auto-compatible vehicle or head unit. ## Using PinePods in Android Auto Connect your phone to your car and PinePods appears as a media app in Android Auto. From there you can browse and play your podcasts using Android Auto's media browser interface, with playback controls and Now Playing information on the car display. ## Playback controls PinePods on Android uses a native media service (built on Media3/ExoPlayer), so playback integrates with the system media controls. That means Android Auto, the lock screen, and notification controls all drive the same playback session for both audio and video podcasts. ## Tips - Download episodes before you drive (see [Downloads](../Features/Downloads.md)) so playback isn't affected by spotty signal on the road. - Queue up episodes ahead of time (see [The Queue](../Features/Queue.md)) and let auto-play carry you through them. --- ## CarPlay (iOS) The PinePods iOS app supports **Apple CarPlay**, so you can browse and control your podcasts safely from your car's display. ## Requirements - The PinePods app installed from the [App Store](https://apps.apple.com/us/app/pinepods/id6751441116) and signed in to your server. - A CarPlay-capable vehicle or head unit. ## Using PinePods in CarPlay Connect your iPhone to your car (via cable or wireless CarPlay, depending on your vehicle) and PinePods appears as an audio app on the CarPlay home screen. From there you can: - Browse your podcasts and episodes using CarPlay's driver-friendly templates. - Start, pause, and skip playback. - See **Now Playing** information — episode title, podcast, and artwork — on the CarPlay display. ## Playback controls PinePods uses a native iOS audio layer, so playback integrates properly with the system: the CarPlay screen, your car's steering-wheel controls, and the lock screen all control the same playback session, and Now Playing metadata and artwork show up everywhere. ## Tips - Download episodes ahead of a drive (see [Downloads](../Features/Downloads.md)) so playback doesn't depend on a cellular connection in the car. - Build a [queue](../Features/Queue.md) before you set off and let auto-play move through it hands-free. --- ## Offline Action Queue (Mobile) The mobile apps keep working when your connection drops. Actions you take while offline — playing, downloading, queueing, and more — are **recorded locally and synced to your server automatically** once you're back online. ## How it works - When the app can't reach your server, your actions are stored in an **offline action queue** on the device instead of being lost. - As soon as connectivity returns, the queued actions are sent to the server and your state catches up — listening progress, queue changes, downloads, and the rest. ## Viewing pending actions The app includes an **action queue** screen where you can see the actions waiting to be synced. This is handy for confirming that something you did offline is still pending and will be applied when you reconnect. ## Why it matters Podcast listening often happens exactly where connectivity is worst — planes, subways, basements, road trips. The offline action queue means your listening on those trips isn't lost; everything reconciles with your server the moment you have a signal again, so your other devices stay in sync too. ## Tips - Pair this with [Downloads](../Features/Downloads.md) and [Auto-Download](../Features/AutoDownload.md) so you have episodes on-device *and* your offline actions sync cleanly later. --- ## Setting Up the Pinepods Mobile App The Pinepods mobile app provides full access to your podcast library on iOS and Android devices, offering seamless synchronization with your Pinepods server and optimized mobile listening experience. This guide covers app installation, server connection, and mobile-specific features. ## Overview The Pinepods mobile app is a Flutter-based application that connects to your Pinepods server, providing: - **Full Library Access**: Complete access to your podcast subscriptions and episodes - **Cross-Platform Sync**: Seamless synchronization with web and desktop clients - **Offline Playback**: Download episodes for offline listening - **Mobile Optimization**: Touch-friendly interface designed for mobile devices - **Background Playback**: Continue listening while using other apps ## App Installation ### iOS Installation #### App Store Download 1. **Open App Store**: Launch the App Store on your iOS device 2. **Search for Pinepods**: Use the search function to find "Pinepods" 3. **Select Official App**: Choose the official Pinepods application 4. **Install**: Tap "Get" or "Install" to download the app 5. **Wait for Installation**: Allow the app to download and install completely #### System Requirements - **iOS Version**: iOS 12.0 or later - **Device Compatibility**: iPhone, iPad, and iPod touch - **Storage Space**: Minimum 100MB free space for app installation - **Network Connection**: Internet access for initial setup and synchronization ### Android Installation The Android app is available on the Google Play Store, as well as through the IzzyOnDroid F-Droid repository, Obtainium, and direct APK download. #### Google Play Store (Recommended) 1. **Open the Play Store**: Launch the Google Play Store on your Android device 2. **Search Application**: Search for "Pinepods", or open the listing directly at [play.google.com](https://play.google.com/store/apps/details?id=com.gooseberrydevelopment.pinepods) 3. **Install**: Tap "Install" to begin the download process 4. **Updates**: Updates arrive automatically through the Play Store #### IzzyOnDroid Prefer F-Droid? Add the [IzzyOnDroid repo](https://apt.izzysoft.de/fdroid/index/apk/com.gooseberrydevelopment.pinepods) and search for "Pinepods" in your F-Droid client; updates arrive automatically through the repo. #### Obtainium For direct updates from GitHub Releases, add PinePods to [Obtainium](https://github.com/madeofpendletonwool/PinePods/releases) and it will track new releases automatically. #### System Requirements - **Android Version**: Android 6.0 (API level 23) or higher - **Storage Space**: Minimum 100MB available storage - **RAM**: At least 2GB RAM recommended for optimal performance - **Network Access**: Internet connectivity for server communication ### Alternative Installation Methods #### Direct APK (Android) For Android users who prefer direct installation: 1. **Download APK**: Obtain the official APK from the Pinepods website or GitHub releases 2. **Enable Unknown Sources**: Allow installation from unknown sources in Android settings 3. **Install APK**: Use a file manager to install the downloaded APK file 4. **Security**: Only download APK files from official Pinepods sources ## Initial App Configuration ### First Launch Setup #### App Permissions Upon first launch, Pinepods may request several permissions: - **Network Access**: Required for connecting to your Pinepods server - **Storage Access**: Needed for downloading and caching episodes - **Notification Access**: For new episode alerts and playback notifications - **Background App Refresh**: Enables background synchronization (iOS) - **Battery Optimization**: Exclude from battery optimization for consistent playback (Android) #### Permission Configuration 1. **Review Requests**: Carefully review each permission request 2. **Grant Access**: Allow necessary permissions for full functionality 3. **Later Configuration**: Most permissions can be adjusted later in device settings 4. **Essential Permissions**: Network and storage access are required for basic functionality ### Server Connection Setup #### Connection Information Required Before connecting, gather the following information: - **Server URL**: Complete URL of your Pinepods server (e.g., `https://pinepods.example.com`) - **Username**: Your Pinepods account username - **Password**: Your account password - **Protocol**: Ensure you use the correct protocol (HTTP or HTTPS) #### Step-by-Step Connection Process ##### Step 1: Enter Server Details 1. **Launch App**: Open the Pinepods mobile app 2. **Server URL Field**: Enter your complete Pinepods server URL 3. **Protocol Verification**: Ensure the URL includes `http://` or `https://` 4. **Port Numbers**: Include port numbers if your server uses non-standard ports ##### Step 2: Authenticate 1. **Username Entry**: Enter your Pinepods username 2. **Password Entry**: Input your account password 3. **Credential Verification**: Double-check your login information 4. **Connection Test**: The app will test the connection to your server ##### Step 3: Connection Verification 1. **Server Response**: App verifies it can communicate with your server 2. **Authentication Check**: Credentials are validated against your Pinepods account 3. **Success Confirmation**: Successful connection displays confirmation message 4. **Error Handling**: Connection errors provide specific troubleshooting information ## Mobile-Specific Features ### Optimized Mobile Interface #### Touch-Friendly Design - **Large Touch Targets**: Buttons and controls sized for easy finger navigation - **Gesture Support**: Swipe gestures for common actions like play/pause and skip - **Responsive Layout**: Interface adapts to different screen sizes and orientations - **Accessibility**: VoiceOver (iOS) and TalkBack (Android) support for accessibility #### Mobile Navigation - **Bottom Navigation**: Primary navigation tabs at the bottom for easy thumb access - **Pull-to-Refresh**: Swipe down to refresh episode feeds and synchronize data - **Search Integration**: Quick search accessible from main navigation - **Context Menus**: Long-press actions for episode and podcast management ### Offline Functionality #### Episode Downloads 1. **Download Options**: Download episodes for offline listening 2. **Quality Settings**: Choose audio quality to balance file size and sound quality 3. **Storage Management**: Monitor and manage downloaded episode storage usage 4. **Auto-Download**: Configure automatic downloads for new episodes (optional) #### Offline Playback - **No Network Required**: Play downloaded episodes without internet connection - **Progress Sync**: Listening progress syncs when connection is restored - **Queue Management**: Manage playback queue even when offline - **Background Play**: Continue listening with screen off or while using other apps ### Background Playback #### Continuous Listening - **Lock Screen Controls**: Control playback from device lock screen - **Notification Controls**: Play/pause and skip controls in notification bar - **App Switching**: Continue listening while switching between apps - **Phone Calls**: Automatic pause/resume during phone calls #### Power Management - **Battery Optimization**: Efficient playback to preserve battery life - **Sleep Timer**: Automatic playback stopping after specified time - **Wake Lock**: Prevent device sleep during active playback - **Background Refresh**: Smart synchronization to balance features and battery usage ## Synchronization and Data Management ### Cross-Device Synchronization #### Automatic Sync Features - **Listening Progress**: Episode playback position syncs across all devices - **Queue Management**: Playback queue synchronizes between web and mobile - **Subscription Updates**: New podcast subscriptions appear on all connected devices - **Episode States**: Completed, saved, and queued episode states sync automatically #### Manual Sync Options - **Pull-to-Refresh**: Manually trigger synchronization by pulling down on episode lists - **Settings Sync**: Force sync through app settings if automatic sync fails - **Logout/Login**: Complete re-synchronization by logging out and back in - **Network Reset**: Reset network connections if sync issues persist ### Storage Management #### Local Storage Options - **Download Location**: Episodes stored in app-specific storage area - **Storage Limits**: Set maximum storage usage for downloaded episodes - **Auto-Cleanup**: Automatic removal of old downloaded episodes - **Manual Management**: View and delete individual downloaded episodes #### Cache Management - **Image Caching**: Podcast artwork cached for faster loading - **Episode Metadata**: Episode information cached for offline browsing - **Cache Clearing**: Options to clear cached data to free up space - **Smart Caching**: Intelligent caching based on usage patterns ## Troubleshooting Mobile App Issues ### Connection Problems #### Server Connection Failures - **URL Verification**: Double-check server URL formatting and spelling - **Network Connectivity**: Ensure device has active internet connection - **Firewall Issues**: Verify corporate or public WiFi doesn't block access - **Server Status**: Confirm your Pinepods server is online and accessible #### Authentication Issues - **Credential Accuracy**: Verify username and password are correct - **Account Status**: Ensure your account is active and not disabled - **Case Sensitivity**: Check for proper capitalization in username and password - **MFA Considerations**: Account for multi-factor authentication if enabled ### Performance Issues #### Slow App Performance - **Device Resources**: Close other apps to free up RAM and processing power - **Storage Space**: Ensure sufficient device storage is available - **Network Speed**: Verify internet connection speed for streaming and sync - **App Restart**: Force close and restart the app to clear temporary issues #### Playback Problems - **Audio Quality**: Adjust streaming quality if experiencing buffering - **Network Stability**: Use WiFi instead of cellular for better stability - **Downloaded Episodes**: Download episodes for reliable offline playback - **Background Apps**: Limit other audio apps that might conflict with playback ### Sync and Data Issues #### Sync Failures - **Manual Refresh**: Try manual sync through pull-to-refresh or settings - **Network Reset**: Reset network settings or switch between WiFi and cellular - **Server Connectivity**: Verify the mobile app can reach your Pinepods server - **Account Verification**: Ensure your account credentials haven't changed #### Missing Data - **Sync Timing**: Allow time for initial synchronization to complete - **Selective Sync**: Check if any sync filters or limitations are configured - **Server Issues**: Verify your Pinepods server is functioning correctly - **Fresh Login**: Log out and log back in to force complete data refresh ## Advanced Mobile Configuration ### Notification Settings #### Episode Notifications - **New Episodes**: Receive notifications when new episodes are available - **Download Complete**: Alerts when episode downloads finish - **Sync Updates**: Notifications for successful synchronization - **Custom Frequency**: Configure notification frequency and timing #### System Integration - **Lock Screen**: Control playback from device lock screen - **Control Center**: Access playback controls from system control center - **Siri Integration**: Voice control for playback on supported devices - **CarPlay/Android Auto**: Integration with vehicle entertainment systems ### Privacy and Security #### Data Protection - **Local Encryption**: Downloaded episodes and cached data are stored securely - **Credential Storage**: Login credentials stored using device keychain/keystore - **Network Security**: All server communication uses secure protocols - **Privacy Settings**: Control what data is shared and synchronized #### Account Security - **Session Management**: Secure session handling for persistent login - **Logout Security**: Complete data clearing when logging out - **Device Management**: Track which devices are connected to your account - **Security Updates**: Keep the app updated for latest security features ## Best Practices for Mobile Usage ### Optimal Configuration 1. **Download Strategy**: Download frequently-listened podcasts for offline access 2. **Quality Settings**: Balance audio quality with storage space and data usage 3. **Sync Frequency**: Configure synchronization to match your usage patterns 4. **Battery Management**: Optimize settings for your device's battery life 5. **Storage Monitoring**: Regularly review and manage downloaded episode storage ### Efficient Usage 1. **WiFi Downloads**: Use WiFi for downloading episodes to save cellular data 2. **Queue Management**: Maintain a manageable playback queue for smooth operation 3. **Regular Updates**: Keep the app updated for latest features and bug fixes 4. **Backup Strategy**: Understand that mobile app data syncs with your server 5. **Network Awareness**: Be mindful of data usage when streaming over cellular ### Troubleshooting Preparation 1. **Server Information**: Keep your server connection details easily accessible 2. **Account Recovery**: Ensure you have password recovery options configured 3. **Support Resources**: Know how to contact your Pinepods administrator 4. **Alternative Access**: Maintain access to the web interface as backup 5. **Update Management**: Stay current with both app and device system updates The Pinepods mobile app provides a comprehensive, portable podcasting experience that maintains full feature parity with the web interface while offering mobile-specific optimizations for on-the-go listening and offline access. --- ## PostgreSQL Collation Version Mismatch Fix ## Problem Description After upgrading PinePods, you may see constant warnings in your PostgreSQL logs like: ``` WARNING: database "pinepods_database" has a collation version mismatch DETAIL: The database was created using collation version 2.36, but the operating system provides version 2.41. HINT: Rebuild all objects in this database that use the default collation and run ALTER DATABASE pinepods_database REFRESH COLLATION VERSION, or build PostgreSQL with the right library version. ``` This occurs when: - Your PinePods database was created with an older version of PostgreSQL - The new PostgreSQL container/version uses updated system libraries - The database's stored collation version doesn't match the current system's collation version **Impact:** This is generally harmless but causes log spam and may cause minor performance issues with text sorting/indexing operations. > **After a major upgrade?** If you just changed PostgreSQL major versions (e.g. > 17 → 18), the underlying `glibc` collation rules genuinely changed, which can affect > text and unique indexes. In that case rebuild your indexes **before** refreshing the > version flag: > > ```bash > docker compose exec db psql -U postgres -d pinepods_database -c "REINDEX DATABASE pinepods_database;" > ``` > > Then run the `REFRESH COLLATION VERSION` commands below. See > [Upgrading PostgreSQL](./PostgresMajorUpgrade.md) for the full upgrade flow. ## Solution ### For Default Docker Setup (PostgreSQL Container) 1. **Find your PostgreSQL container name:** ```bash docker ps ``` Look for the PostgreSQL container (usually named something like `db`, `postgres_db`, or `pinepods_db`) 2. **Connect to PostgreSQL and fix the collation version:** ```bash docker exec -it psql -U postgres -d pinepods_database -c "ALTER DATABASE pinepods_database REFRESH COLLATION VERSION;" ``` Example: ```bash docker exec -it postgres_db psql -U postgres -d pinepods_database -c "ALTER DATABASE pinepods_database REFRESH COLLATION VERSION;" ``` 3. **Expected output:** ``` NOTICE: version has not changed ALTER DATABASE ``` or ``` ALTER DATABASE ``` 4. **Check for additional database warnings:** After fixing the main PinePods database, you may see similar warnings for the default `postgres` database: ``` WARNING: database "postgres" has a collation version mismatch ``` If this occurs, run the same fix for the postgres database: ```bash docker exec -it psql -U postgres -d postgres -c "ALTER DATABASE postgres REFRESH COLLATION VERSION;" ``` ### For External PostgreSQL Database 1. **Connect to your external PostgreSQL server** using your preferred method: - Command line: `psql -h -U -d pinepods_database` - GUI tools like pgAdmin, DBeaver, etc. - Your cloud provider's console (AWS RDS, Google Cloud SQL, etc.) 2. **Run the collation refresh command:** ```sql ALTER DATABASE pinepods_database REFRESH COLLATION VERSION; ``` 3. **Check for additional database warnings:** You may also need to fix the default `postgres` database if you see warnings for it: ```sql ALTER DATABASE postgres REFRESH COLLATION VERSION; ``` 4. **If you have multiple PinePods databases** (unlikely but possible), repeat for each: ```sql ALTER DATABASE your_other_pinepods_db REFRESH COLLATION VERSION; ``` ### For Docker Compose Users If you're using Docker Compose, you can run: ```bash # Fix the main PinePods database docker compose exec db psql -U postgres -d pinepods_database -c "ALTER DATABASE pinepods_database REFRESH COLLATION VERSION;" # Fix the postgres and template1 system databases if needed docker compose exec db psql -U postgres -d postgres -c "ALTER DATABASE postgres REFRESH COLLATION VERSION;" docker compose exec db psql -U postgres -d template1 -c "ALTER DATABASE template1 REFRESH COLLATION VERSION;" ``` Replace `db` with your PostgreSQL service name from your `docker-compose.yml` file. ## Verification After running the command: 1. **Check your logs** - the collation warnings should stop appearing 2. **Restart PinePods** (optional but recommended) to ensure clean startup 3. **Monitor logs** for a few minutes to confirm the warnings are gone ## Alternative Database Names If your database is named something other than `pinepods_database`, replace it in the commands above. Common variations: - `pinepods` - `pinepods_db` - `podcast_database` You can find your actual database name by connecting to PostgreSQL and running: ```sql \l ``` ## When This Issue Occurs This issue typically happens when: - Upgrading from older PinePods versions (especially major version jumps) - Moving from one PostgreSQL version to another - Migrating between different hosting environments - Updating Docker images that include newer PostgreSQL versions ## Prevention for Future Upgrades Unfortunately, this is a PostgreSQL-level issue that can occur with any database application during major upgrades. The fix is simple and only needs to be run once after each major PostgreSQL version upgrade. ## Need Help? If you encounter issues with these steps: 1. Check that you're connecting to the correct database container/server 2. Verify your database name is correct 3. Ensure you have sufficient privileges to run `ALTER DATABASE` commands 4. Open an issue on the PinePods GitHub repository with your specific error message --- ## PostgreSQL 18 Docker Container Issue ## Overview A critical issue affects PostgreSQL version 18 Docker containers that prevents them from starting properly when using standard volume mount configurations. This issue is related to changes in how PostgreSQL 18 handles the `PGDATA` directory structure within Docker containers. ## The Problem When attempting to start a PostgreSQL 18 container, you may encounter an error similar to: ``` Failed to deploy a stack: compose up operation failed: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "" to rootfs at "/var/lib/postgresql/data": change mount propagation through procfd: open o_path procfd: open //overlay2/17561d31d0730b3fd3071752d82cf8fe60b2ea0ed84521c6ee8b06427ca8f064/merged/var/lib/postgresql/data: no such file or directory: unknown ``` ## Root Cause This issue stems from an intentional breaking change introduced in PostgreSQL 18 Docker images. The PostgreSQL Docker maintainers modified the `PGDATA` path structure to better align with upstream PostgreSQL expectations and facilitate future major version upgrades. **Key Changes in PostgreSQL 18:** - The default `PGDATA` path changed from `/var/lib/postgresql/data` to `/var/lib/postgresql/18/docker` - The `/var/lib/postgresql/data` directory is now a symbolic link, which breaks direct volume mounting - This change affects how volumes must be mounted and configured ## Impact on Pinepods **Current Status:** Pinepods is currently **untested** with PostgreSQL 18. While it will likely work with proper configuration adjustments, we recommend using PostgreSQL 17 for production deployments until full compatibility testing is completed. ## Solutions ### Recommended Solution: Use PostgreSQL 17 The simplest and most reliable solution is to specify PostgreSQL 17 in your Docker Compose configuration: ```yaml services: postgres: image: postgres:17 volumes: - ./data/database:/var/lib/postgresql/data environment: POSTGRES_DB: pinepods POSTGRES_USER: postgres POSTGRES_PASSWORD: your_password ``` ### Alternative Solutions (For PostgreSQL 18) If you need to use PostgreSQL 18, here are three working approaches: #### Option 1: Mount to Parent Directory (Recommended for v18) ```yaml services: postgres: image: postgres:18 volumes: - ./data/database:/var/lib/postgresql environment: POSTGRES_DB: pinepods POSTGRES_USER: postgres POSTGRES_PASSWORD: your_password ``` With this configuration, your data will be stored in `./data/database/18/docker/`. #### Option 2: Explicit PGDATA Configuration ```yaml services: postgres: image: postgres:18 volumes: - ./data/database:/var/lib/postgresql/18/data environment: POSTGRES_DB: pinepods POSTGRES_USER: postgres POSTGRES_PASSWORD: your_password PGDATA: /var/lib/postgresql/18/data ``` #### Option 3: Custom PGDATA Path ```yaml services: postgres: image: postgres:18 volumes: - ./data/database:/custom/data/path environment: POSTGRES_DB: pinepods POSTGRES_USER: postgres POSTGRES_PASSWORD: your_password PGDATA: /custom/data/path ``` ## Migration Considerations ### From PostgreSQL 17 to 18 If you're migrating from PostgreSQL 17 to 18: 1. **Backup your data** first using `pg_dump` 2. **Stop your containers** 3. **Update your Docker Compose file** using one of the solutions above 4. **Restore your data** using `pg_restore` or similar tools ### Data Directory Changes Be aware that PostgreSQL 18 uses a different directory structure: - **PostgreSQL 17:** Data stored directly in mounted volume - **PostgreSQL 18:** Data stored in versioned subdirectory (e.g., `18/docker/`) ## Related Links - [Official PostgreSQL Docker Issue #1363](https://github.com/docker-library/postgres/issues/1363) --- **Note:** This issue affects all applications using PostgreSQL Docker containers, not just Pinepods. The solutions provided here are general Docker PostgreSQL fixes that should work with any application. --- ## Upgrading PostgreSQL (e.g. 17 → 18) ## Problem Description When you change your `db` container image to a newer PostgreSQL major version (for example from `postgres:17` to `postgres:18`) and start the stack, the database container refuses to start and crash-loops with: ``` FATAL: database files are incompatible with server DETAIL: The data directory was initialized by PostgreSQL version 17, which is not compatible with this version 18.4 (Debian 18.4-1.pgdg13+1). ``` Pinepods itself will then sit waiting for a database that never comes up: ``` WARNING - Connection attempt 1/30 failed: server closed the connection unexpectedly ``` **This is normal PostgreSQL behavior, not a Pinepods bug.** Every PostgreSQL *major* version uses an incompatible on-disk data-directory format. A version 18 server will not read a data directory that was created (`initdb`) by version 17 — it must be upgraded first. **Your data is not lost**; it is simply bound to the older server until you run an upgrade. > **Minor** version upgrades (e.g. `18.3` → `18.4`) are safe and need none of this — > only **major** version jumps (17 → 18) require the steps below. ## Before You Start: Back Up A major-version upgrade rewrites the data directory. Always take a backup first: 1. Create a server backup from inside Pinepods — see [Server Backup and Restore](../tutorial-basics/Backup-Restore.md). 2. **Also** stop the whole stack (`docker compose down`) and copy your `pgdata` host directory somewhere safe: ```bash cp -a /home/user/pinepods/pgdata /home/user/pinepods/pgdata.v17-backup ``` This copy is your guaranteed rollback point (see [Rolling Back](#rolling-back-can-i-go-back-to-17) below). ## Recommended Path: pgautoupgrade (automatic, in-place) The easiest way to upgrade is the drop-in [`pgautoupgrade`](https://github.com/pgautoupgrade/docker-pgautoupgrade) image. It detects the version your data directory was created with, runs `pg_upgrade` in place, and then runs as the new version — using the **same** volume you already have. > **Use the Debian (`-trixie`) variant.** The official `postgres:18` image is built on > Debian (the error above shows `pgdg13` = Debian 13 / *trixie*). Matching that with > `pgautoupgrade/pgautoupgrade:18-trixie` keeps the system locale/collation libraries > consistent so your indexes stay valid. Avoid mixing the Alpine variant with the > Debian `postgres` image. ### Option 1 — Helper script (simplest) Pinepods ships a helper that takes a safety dump, runs the one-shot upgrade, and tells you what to change. From a checkout of the Pinepods repo: ```bash ./deployment/docker/upgrade-postgres.sh --help ``` Follow its prompts, then continue with [After the Upgrade](#after-the-upgrade) below. ### Option 2 — Manual, with your existing compose file 1. **Stop the stack:** ```bash docker compose down ``` 2. **Temporarily** point the `db` service at `pgautoupgrade` and tell it to upgrade then exit. Keep the **same host path** and `POSTGRES_*` values you already use, but move the mount and `PGDATA` to `/var/lib/pgdata` (see the note below): ```yaml services: db: container_name: db image: pgautoupgrade/pgautoupgrade:18-trixie # was postgres:17 environment: POSTGRES_DB: pinepods_database POSTGRES_USER: postgres POSTGRES_PASSWORD: myS3curepass PGDATA: /var/lib/pgdata/pgdata PGAUTO_ONESHOT: "yes" # upgrade, then exit volumes: - /home/user/pinepods/pgdata:/var/lib/pgdata ``` > **Why the path changes from `/var/lib/postgresql/data` to `/var/lib/pgdata`:** the > `postgres:18` image (which `pgautoupgrade:18-trixie` is based on) declares > `/var/lib/postgresql` as a `VOLUME`. Bind-mounting *under* it can fail on some > Linux/overlay2 hosts with `change mount propagation ... no such file or directory` > ([docker-library/postgres#1363](https://github.com/docker-library/postgres/issues/1363)). > Mounting at `/var/lib/pgdata` sidesteps this. Your **host** path is unchanged, so > no files move on disk — the cluster still lives at `/home/user/pinepods/pgdata/pgdata`. 3. **Run only the database** and let it upgrade. With `PGAUTO_ONESHOT=yes` the container performs the upgrade and exits cleanly (exit code 0): ```bash docker compose up db ``` Watch the logs — you should see it detect the old version and run `pg_upgrade` successfully, then stop. 4. **Switch back to the stock image** and remove the one-shot variable. Keep the `/var/lib/pgdata` mount and `PGDATA` from step 2. Your data directory is now version 18: ```yaml services: db: image: postgres:18 # was pgautoupgrade environment: POSTGRES_DB: pinepods_database POSTGRES_USER: postgres POSTGRES_PASSWORD: myS3curepass PGDATA: /var/lib/pgdata/pgdata # PGAUTO_ONESHOT removed volumes: - /home/user/pinepods/pgdata:/var/lib/pgdata ``` 5. **Start everything normally:** ```bash docker compose up -d ``` PostgreSQL should start with no "incompatible" error and Pinepods should connect. ## After the Upgrade The new image almost always ships a newer `glibc` than the one your data was created with, so the `db` logs will warn about a **collation version mismatch** (e.g. "created using collation version 2.36, but the operating system provides version 2.41"). This is expected. Because the system collation actually changed, the correct fix is to **rebuild indexes first**, then clear the version flag on every database that warns (including the system `postgres` and `template1` databases): ```bash # Rebuild indexes on your real database (protects text/unique indexes) docker compose exec db psql -U postgres -d pinepods_database \ -c "REINDEX DATABASE pinepods_database;" # Clear the collation version flag on every database that warns docker compose exec db psql -U postgres -d pinepods_database \ -c "ALTER DATABASE pinepods_database REFRESH COLLATION VERSION;" docker compose exec db psql -U postgres -d postgres \ -c "ALTER DATABASE postgres REFRESH COLLATION VERSION;" docker compose exec db psql -U postgres -d template1 \ -c "ALTER DATABASE template1 REFRESH COLLATION VERSION;" ``` The `postgres` and `template1` databases are empty system databases, so they only need the `REFRESH` — no reindex. See [PostgreSQL Collation Version Mismatch Fix](./CollationVersionMismatchFix.md) for more detail. Once the upgrade looks healthy and Pinepods works, you can delete the `pgdata.v17-backup` copy and the safety dump. ## Rolling Back: Can I Go Back to 17? **Not in place.** A major upgrade is one-way for a given data directory — once it is at version 18, a version 17 server can no longer read it. There is no "swap back and forth" between major versions against the same `pgdata`. To return to 17 you must restore from a pre-upgrade backup: - **Fastest:** stop the stack, delete the upgraded `pgdata`, and put your `pgdata.v17-backup` copy back in its place. Set the image back to `postgres:17` and start. - **Or:** start a fresh `postgres:17` stack with an empty data directory and restore your Pinepods server backup into it. This is exactly why the [backup step](#before-you-start-back-up) above is not optional. ## Alternative Path: Manual dump and restore If you prefer not to use `pgautoupgrade`, you can migrate logically. This is fully version-independent: 1. With the stack on `postgres:17`, dump everything: ```bash docker exec -t db pg_dumpall -U postgres > pinepods-all.sql ``` 2. Stop the stack, move the old data directory aside, and point the volume at a new empty directory. Set the `db` image to `postgres:18` and use the `VOLUME`-safe mount from the [recommended path](#option-2--manual-with-your-existing-compose-file) (`PGDATA: /var/lib/pgdata/pgdata`, mounted at `/var/lib/pgdata`). 3. Start only `db` so version 18 initializes a fresh data directory, then restore: ```bash cat pinepods-all.sql | docker exec -i db psql -U postgres ``` 4. Start the rest of the stack as normal. --- ## Getting Started PinePods is a Rust based podcast management system that manages podcasts with multi-user support and relies on a central database with clients to connect to it. It's browser based and your podcasts and settings follow you from device to device due to everything being stored on the server. You can subscribe to podcasts and even hosts for podcasts with the help of the PodPeopleDB. It works on mobile devices and can also sync with a Nextcloud server or gpodder compatible sync server so you can use external apps like Antennapod as well! ![The PinePods home dashboard](/img/screenshots/homepage.png) ## Features Pinepods is a complete podcast management system and allows you to play, download, and keep track of podcasts you (or any of your users) enjoy. It allows for searching and subscribing to hosts and podcasts using The Podcast Index or Itunes and provides a modern looking UI to browse through shows and episodes. In addition, Pinepods provides simple user management and can be used by multiple users at once using a browser or app version. Everything is saved into a MySQL or Postgres database including user settings, podcasts and episodes. It's fully self-hosted, open-sourced, and I provide an option to use a hosted search API or you can also get one from the Podcast Index and use your own. There's even many different themes to choose from! Everything is fully dockerized and I provide a simple guide found below explaining how to install and run Pinepods on your own system. ## Try it out! :zap: I maintain an instance of Pinepods that's publicly accessible for testing over at [try.pinepods.online](https://try.pinepods.online). Feel free to make an account there and try it out before making your own server instance. This is not intended as a permanant method of using Pinepods and it's expected you run your own server so accounts will often be deleted from there. ## Installing :runner: There's potentially a few steps to getting Pinepods fully installed. After you get your server up and running fully you can also install the client editions of your choice. The server install of Pinepods runs a server and a browser client over a port of your choice in order to be accessible on the web. With the client installs you simply give the client your server url to connect to the database and then sign in. ### Server Installation :floppy_disk: First, the server. You have multiple options for deploying Pinepods: - [Using Docker Compose :whale:](#docker-compose) - [Using Helm for Kubernetes :anchor:](#helm-deployment) You can also choose to use MySQL/MariaDB or Postgres as your database. Examples for both are provided below. ### Docker Compose :::note PostgreSQL 18 data path The `postgres:18` image moved its data directory and declared `VOLUME` to `/var/lib/postgresql`. Bind-mounting to the old `/var/lib/postgresql/data` can fail on some Linux/overlay2 hosts with `change mount propagation through procfd ... no such file or directory`. The compose below avoids this by mounting at `/var/lib/pgdata` (outside the image's `VOLUME`) — use that pattern and you won't hit the error. See [docker-library/postgres#1363](https://github.com/docker-library/postgres/issues/1363). Already running Postgres 17? See [Upgrading PostgreSQL](/docs/Troubleshooting/PostgresMajorUpgrade). ::: #### User Permissions Pinepods can run as a non-root user so downloaded files are accessible on the host system. This is controlled through two environment variables: - `PUID`: Process User ID — the host user the stack runs as - `PGID`: Process Group ID — the host group the stack runs as When `PUID`/`PGID` are set, `startup.sh` remaps the container's `pinepods` user to those IDs and drops privileges with `su-exec`, so the entire stack runs as your host user. The compose examples below pass `${UID:-911}`/`${GID:-911}`, so they fall back to `911` if `UID`/`GID` aren't exported in your shell. If `PUID`/`PGID` are left unset entirely, the container runs as root (legacy mode). To find your user's UID and GID, run: ```bash id -u # Your UID id -g # Your GID ``` #### Compose File - PostgreSQL (Recommended) ```yaml services: db: container_name: db image: postgres:18 environment: POSTGRES_DB: pinepods_database POSTGRES_USER: postgres POSTGRES_PASSWORD: myS3curepass PGDATA: /var/lib/pgdata/pgdata volumes: - /home/user/pinepods/pgdata:/var/lib/pgdata ports: - "5432:5432" restart: always valkey: image: valkey/valkey:8-alpine restart: always pinepods: image: madeofpendletonwool/pinepods:latest ports: - "8040:8040" environment: # Basic Server Info SEARCH_API_URL: 'https://search.pinepods.online/api/search' PEOPLE_API_URL: 'https://people.pinepods.online' HOSTNAME: 'http://localhost:8040' # Database Vars DB_TYPE: postgresql DB_HOST: db DB_PORT: 5432 DB_USER: postgres DB_PASSWORD: myS3curepass DB_NAME: pinepods_database # Valkey Settings VALKEY_HOST: valkey VALKEY_PORT: 6379 # Enable or Disable Debug Mode for additional Printing DEBUG_MODE: false PUID: ${UID:-911} PGID: ${GID:-911} # Add timezone configuration TZ: "America/New_York" volumes: # Mount the download and backup locations on the server - /home/user/pinepods/downloads:/opt/pinepods/downloads - /home/user/pinepods/backups:/opt/pinepods/backups # Timezone volumes, HIGHLY optional. Read the timezone notes below - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro restart: always depends_on: - db - valkey ``` :::info Upgrading an existing Postgres 17 install to 18? New installs default to `postgres:18` and need no special steps. **Existing** installs can't just bump the tag — a major Postgres version uses an incompatible on-disk format, so `postgres:18` will refuse to start against a directory created by 17. Your data is safe; it just needs a one-time upgrade. Run the helper script `deployment/docker/upgrade-postgres.sh` (takes a backup, then upgrades in place) or follow the [Upgrading PostgreSQL](/docs/Troubleshooting/PostgresMajorUpgrade) guide. Always back up first — the upgrade is one-way. ::: #### Compose File - MariaDB (Alternative) ```yaml services: db: container_name: db image: mariadb:12 command: --wait_timeout=1800 environment: MYSQL_TCP_PORT: 3306 MYSQL_ROOT_PASSWORD: myS3curepass MYSQL_DATABASE: pinepods_database MYSQL_COLLATION_SERVER: utf8mb4_unicode_ci MYSQL_CHARACTER_SET_SERVER: utf8mb4 MYSQL_INIT_CONNECT: 'SET @@GLOBAL.max_allowed_packet=64*1024*1024;' volumes: - /home/user/pinepods/sql:/var/lib/mysql restart: always valkey: image: valkey/valkey:8-alpine pinepods: image: madeofpendletonwool/pinepods:latest ports: - "8040:8040" environment: # Basic Server Info SEARCH_API_URL: 'https://search.pinepods.online/api/search' PEOPLE_API_URL: 'https://people.pinepods.online' HOSTNAME: 'http://localhost:8040' # Database Vars DB_TYPE: mariadb DB_HOST: db DB_PORT: 3306 DB_USER: root DB_PASSWORD: myS3curepass DB_NAME: pinepods_database # Valkey Settings VALKEY_HOST: valkey VALKEY_PORT: 6379 # Enable or Disable Debug Mode for additional Printing DEBUG_MODE: false PUID: ${UID:-911} PGID: ${GID:-911} # Add timezone configuration TZ: "America/New_York" volumes: # Mount the download and backup locations on the server - /home/user/pinepods/downloads:/opt/pinepods/downloads - /home/user/pinepods/backups:/opt/pinepods/backups # Timezone volumes, HIGHLY optional. Read the timezone notes below - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro depends_on: - db - valkey ``` Make sure you change these variables to variables specific to yourself at a minimum. ``` # The url you hit the site at. Only used for sharing rss feeds HOSTNAME: 'http://localhost:8040' # These next 4 are optional. They allow you to set an admin without setting on the first boot USERNAME: pinepods PASSWORD: password FULLNAME: John Pinepods EMAIL: john@pinepods.com # DB vars should match your values for the db you set up above DB_TYPE: postgresql DB_HOST: db DB_PORT: 5432 DB_USER: postgres DB_PASSWORD: myS3curepass DB_NAME: pinepods_database ``` Most of those are pretty obvious, but let's break a couple of them down. #### Admin User Info First of all, the USERNAME, PASSWORD, FULLNAME, and EMAIL vars are your details for your default admin account. This account will have admin credentials and will be able to log in right when you start up the app. Once started you'll be able to create more users and even more admins, but you need one account to kick things off. If you don't specify these credentials in the compose file, PinePods will prompt you to create your first admin account when you open the web UI for the first time — so setting them is optional. #### Note on the Search API Let's talk quickly about the searching API. This allows you to search for new podcasts and it queries iTunes, the Podcast Index, or YouTube for new content. The Podcast Index and YouTube (via the Google Search API) both require an API key, while iTunes does not. Note that Google enforces a daily quota on YouTube searches, so heavy YouTube users will want to self-host. If you'd rather not mess with the API at all simply set the API_URL to the one below. ``` SEARCH_API_URL: 'https://search.pinepods.online/api/search' ``` Above is an api that I maintain. I do not guarantee 100% uptime on this api though, it should be up most of the time besides a random internet or power outage here or there. A better idea though, and what I would honestly recommend is to maintain your own api. It's super easy. Check out the API docs for more information on doing this. Link Below - https://www.pinepods.online/docs/API/search_api #### Timezone Configuration PinePods supports displaying timestamps in your local timezone instead of UTC. This helps improve readability and prevents confusion when viewing timestamps such as "last sync" times in the gpodder API. Note that this configuration is specifically for logs. Each user sets their own timezone settings on first login. That is seperate from this server timezone config. ##### Setting the Timezone You have two main options for configuring the timezone in PinePods: ##### Option 1: Using the TZ Environment Variable (Recommended) Add the `TZ` environment variable to your docker-compose.yml file: ```yaml services: pinepods: image: madeofpendletonwool/pinepods:latest environment: # Other environment variables... TZ: "America/Chicago" # Set your preferred timezone ``` This method works consistently across all operating systems (Linux, macOS, Windows) and is the recommended approach. ##### Option 2: Mounting Host Timezone Files (Linux Only) On Linux systems, you can mount the host's timezone files: ```yaml services: pinepods: image: madeofpendletonwool/pinepods:latest volumes: # Other volumes... - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro ``` **Note**: This method only works reliably on Linux hosts. For macOS and Windows users, please use the TZ environment variable (Option 1). ##### Priority If both methods are used: 1. The TZ environment variable takes precedence 2. Mounted timezone files are used as a fallback ##### Common Timezone Values Here are some common timezone identifiers: - `America/New_York` - Eastern Time - `America/Chicago` - Central Time - `America/Denver` - Mountain Time - `America/Los_Angeles` - Pacific Time - `Europe/London` - United Kingdom - `Europe/Berlin` - Central Europe - `Asia/Tokyo` - Japan - `Australia/Sydney` - Australia Eastern For a complete list of valid timezone identifiers, see the [IANA Time Zone Database](https://www.iana.org/time-zones). ##### Troubleshooting Timezones **I'm on macOS and timezone settings aren't working** macOS uses a different timezone file format than Linux. You must use the TZ environment variable method on macOS. #### Start it up! Either way, once you have everything all setup and your compose file created go ahead and run ``` sudo docker-compose up ``` To pull the container images and get started. Once fully started up you'll be able to access pinepods at the port you configured and you'll be able to start connecting clients as well. ### Helm Deployment Alternatively, you can deploy Pinepods using Helm on a Kubernetes cluster. Helm is a package manager for Kubernetes that simplifies deployment. #### Adding the Helm Repository First, add the Pinepods Helm repository: ```bash helm repo add pinepods http://helm.pinepods.online helm repo update ``` #### Installing the Chart To install the Pinepods Helm chart with default values: ```bash helm install pinepods pinepods/pinepods --namespace pinepods-namespace --create-namespace ``` Or with custom values: ```bash helm install pinepods pinepods/pinepods -f my-values.yaml --namespace pinepods-namespace --create-namespace ``` #### Configuration Options The Helm chart supports extensive configuration. Key areas include: **Main Application:** - Image repository and tag configuration - Service type and port settings - Ingress configuration with TLS support - Persistent storage for downloads and backups - Resource limits and requests - Security contexts and pod placement **Dependencies:** - PostgreSQL database (can be disabled for external database) - Valkey/Redis for caching (can be disabled) - Optional backend API deployment for self-hosted search - Optional PodPeople database for podcast host information **Example values.yaml:** ```yaml # Main application configuration image: repository: madeofpendletonwool/pinepods tag: latest pullPolicy: IfNotPresent service: type: ClusterIP port: 8040 ingress: enabled: true className: "" annotations: traefik.ingress.kubernetes.io/router.entrypoints: web hosts: - host: pinepods.example.com paths: - path: / pathType: Prefix tls: [] # Persistent storage persistence: enabled: true downloads: storageClass: "" # Use default storage class size: 5Gi backups: storageClass: "" size: 2Gi # Database configuration postgresql: enabled: true auth: username: postgres password: "changeme" database: pinepods_database persistence: enabled: true size: 3Gi # Valkey/Redis configuration valkey: enabled: true architecture: standalone auth: enabled: false # Optional backend API (self-hosted search) backend: enabled: false secrets: apiKey: "YOUR_PODCAST_INDEX_KEY" apiSecret: "YOUR_PODCAST_INDEX_SECRET" # Optional PodPeople database podpeople: enabled: false # Application environment env: USERNAME: "admin" PASSWORD: "password" FULLNAME: "Admin User" EMAIL: "admin@example.com" DEBUG_MODE: "false" HOSTNAME: 'http://localhost:8040' ``` #### External Database Configuration To use an external database instead of the included PostgreSQL: ```yaml postgresql: enabled: false externalDatabase: host: "your-postgres-host" port: 5432 user: postgres password: "your-password" database: pinepods_database ``` #### Create a Namespace for Pinepods Create a namespace to hold the deployment: ```bash kubectl create namespace pinepods-namespace ``` #### Starting Helm Once you have everything set up, install the Helm chart: ```bash helm install pinepods pinepods/pinepods -f my-values.yaml --namespace pinepods-namespace --create-namespace ``` This will deploy Pinepods on your Kubernetes cluster with a postgres database. MySQL/MariaDB is not supported with the kubernetes setup. The service will be accessible at the specified NodePort. Check out the Tutorials on the documentation site for more information on how to do basic things. [Tutorial: Signing in & the home screen](/docs/tutorial-basics/sign-in-homescreen) ## Client Installs Any of the client additions are super easy to get going. ### Linux Client Installs :computer: #### AppImage, Fedora/Red Hat Derivative/Debian based (Ubuntu) First head over to the releases page on Github https://github.com/madeofpendletonwool/PinePods/releases Grab the latest linux release. There's both an appimage a deb, and an rpm. Use the appimage of course if you aren't using a debian or red hat based distro. Change the permissions if using the appimage version to allow it to run. ``` sudo chmod +x pinepods.appimage ``` ^ The name of the app file will vary slightly based on the version so be sure you change it or it won't work. For the rpm or deb version just run and install Once started you'll be able to sign in with your username and password. The server name is simply the url you browse to to access the server. #### Arch Linux (AUR) Install the Pinepods Client right from the AUR! Replace the command below with your favorite aur helper ``` paru -S pinepods ``` #### Flatpak You can search for Pinepods in your favorite flatpak installer gui app such as Gnome Software. Flathub page can be found [here](https://flathub.org/apps/com.gooseberrydevelopment.pinepods) ``` flatpak install flathub com.gooseberrydevelopment.pinepods ``` #### Snap I have had such a nightmare trying to make the snap client work. Pass, use the flatpak. They're better anyway. I'll test it again in the future and see if Canonical has gotten it together. If you really want a snap version of the client please reach out and tell me you're interested in the first place. #### Windows Client Install :computer: Any of the client additions are super easy to get going. First head over to the releases page on Github https://github.com/madeofpendletonwool/PinePods/releases There's a exe and msi windows install file. The exe will actually start an install window and allow you to properly install the program to your computer. The msi will simply run a portable version of the app. Either one does the same thing ultimately and will work just fine. Once started you'll be able to sign in with your username and password. The server name is simply the url you browse to to access the server. #### Mac Client Install :computer: Any of the client additions are super easy to get going. First head over to the releases page on Github https://github.com/madeofpendletonwool/PinePods/releases There's a dmg and pinepods_mac file. Simply extract, and then go into Contents/MacOS. From there you can run the app. The dmg file will prompt you to install the Pinepods client into your applications fileter while the _mac file will just run a portable version of the app. Once started you'll be able to sign in with your username and password. The server name is simply the url you browse to to access the server. #### Android Install :iphone: The Android app is available now on the [Google Play Store](https://play.google.com/store/apps/details?id=com.gooseberrydevelopment.pinepods)! You can also install it from [IzzyOnDroid](https://apt.izzysoft.de/fdroid/index/apk/com.gooseberrydevelopment.pinepods) or via [Obtainium](https://github.com/madeofpendletonwool/PinePods/releases) for direct updates from GitHub Releases. Android Auto is supported. Once installed, sign in with your username and password. The server name is simply the URL you browse to to access the server. #### iOS Install :iphone: The iOS app is on the [App Store](https://apps.apple.com/us/app/pinepods/id6751441116)! CarPlay is supported. Once installed, sign in with your username and password. The server name is simply the URL you browse to to access the server. ## PodPeople DB Podpeople DB is a project that I maintain and also develop. Podpeople DB is a way to suppliment Person tags for podcasts that don't support them by default. This allows the community to maintain hosts and follow them to all podcasts! I maintain an instance of Podpeople DB at podpeopledb.com. Otherwise, it's an open source project and you can maintain and instance of your own if you prefer. For information on that go [here](https://podpeopledb.com/docs/self-host). You can download the database yourself and maintain your own instance. If you do decide to go this route please still add any hosts for your favorite podcasts at the instance hosted at podpeopledb.com. The community will thank you! For additional info on Podpeople DB check out [the docs](https://podpeopledb.com/docs/what-is-this-for). Additionally, I've written [a blog](https://www.pinepods.online/blog) post discussing the rational around it's creation. Finally, you can check out the Repo for it [here!](https://github.com/madeofpendletonwool/podpeople-db) ## Pinepods Firewood A CLI-only client that lets you enjoy your podcasts from the comfort of the terminal has had its first release! Check out [Pinepods Firewood!](https://github.com/madeofpendletonwool/pinepods-firewood) ## Platform Availability PinePods is available on **Windows, Linux, macOS, web, Android, and iOS** — all shipped and working today. The desktop clients are built with Tauri, while the mobile apps (Android and iOS) are native Flutter apps with native audio layers, CarPlay, and Android Auto support. PinePods also runs a **built-in gpodder-compatible sync server**, so you can keep using external apps like AntennaPod and have them stay in sync with PinePods automatically — no separate sync server required. If you'd prefer an external sync server, OpodSync and the Nextcloud gpodder sync app both work great too. [OpodSync](https://github.com/kd2org/opodsync) [Nextcloud Podcast Sync App](https://apps.nextcloud.com/apps/gpoddersync) ARM devices are also supported including raspberry pis. The app is shockingly performant on a raspberry pi as well. The only limitation is that a 64bit OS is required on an arm device. Setup is exactly the same, just use the latest tag and docker will auto pull the arm version. #### Runners Arm Images made possible by Runs-On: https://runs-on.com --- ## Adjusting User Settings The User Settings section allows administrators to manage user accounts within their Pinepods instance. This comprehensive interface provides tools for creating, modifying, and managing user accounts, including their permissions and personal information. ## Accessing User Settings To access User Settings: 1. Navigate to the **Settings** page from the main menu 2. Expand the **User Settings** accordion section 3. Only users with administrative privileges will see this section ## User Management Features ### Creating New Users Administrators can create new user accounts with the following steps: 1. Click the **Add User** or **Create User** button 2. Fill in the required information: - **Username**: Must be at least 3 characters long and unique - **Password**: Must be at least 8 characters long for security - **Email**: Valid email address for notifications and password resets - **Full Name**: Display name for the user - **Admin Status**: Toggle to grant or deny administrative privileges 3. Click **Create** to add the new user ### Input Validation The system enforces several validation rules: - **Username**: Minimum 3 characters, must be unique across the system - **Password**: Minimum 8 characters for security compliance - **Email**: Must be a valid email format (user@domain.com) Error messages will appear if validation fails, clearly indicating what needs to be corrected. ### Viewing Existing Users The User Settings interface displays a list of all current users showing: - Username - Full name - Email address - Administrative status - User ID (for reference) ### Modifying User Information For each existing user, administrators can modify: #### Basic Information - **Username**: Change the login name (must remain unique) - **Full Name**: Update the display name - **Email Address**: Change the contact email #### Security Settings - **Password**: Reset or change user passwords - **Admin Privileges**: Grant or revoke administrative access #### Account Management - **Delete User**: Remove user accounts (use with caution) ## Administrative Controls ### Admin Status Management Administrators can: - **Grant Admin Rights**: Give users administrative privileges - **Revoke Admin Rights**: Remove administrative access - **View Admin Status**: Clearly see which users have administrative privileges ### Security Considerations - Password changes are encrypted using secure hashing - Administrative actions are logged for security auditing - Only existing administrators can modify user permissions - Users cannot elevate their own privileges --- ## Server Backup and Restore Pinepods provides comprehensive server-level backup and restore functionality that allows administrators to create full database backups and restore their entire Pinepods instance. This feature is essential for data protection, server migration, and disaster recovery. ## Overview The backup and restore system creates complete SQL dumps of your Pinepods database, including: - All user accounts and authentication data - Complete podcast subscriptions and metadata - Episode information and listening history - User settings and preferences - API keys and integrations - Server configuration settings - Literally everything ## Accessing Backup and Restore **Administrator Access Required** 1. Navigate to **Settings** in the main menu 2. Expand the settings sections to find: - **Backup Server Data** section - **Restore Server Data** section 3. Only users with administrative privileges can access these features ## Creating Server Backups ### Backup Process The backup feature generates a complete SQL dump of your Pinepods database that can be used to restore your server or migrate to a new instance. #### Step-by-Step Backup 1. Locate the **Backup Server Data** section in settings 2. Enter your **database password** in the provided field 3. Click the **Download Backup** button 4. The system will generate a backup file named `server_backup.sql` 5. The file will automatically download to your device ## Restoring Server Data ### Restore Process The restore functionality allows you to restore a complete Pinepods instance from a previously created backup file. #### Prerequisites for Restore - Valid backup file (`.sql` format from Pinepods backup) - Database password used during backup creation - Administrative access to the target server - Understanding that restore overwrites existing data #### Step-by-Step Restore 1. Locate the **Restore Server Data** section in settings 2. Click **Choose File** to select your backup file 3. Enter the **database password** used when creating the backup 4. Click **Restore Server** to begin the process 5. The system will process the restore and redirect you to sign out 6. Log back in with your restored credentials #### File Limitations - **Supported Format**: Only SQL files created by Pinepods backup - **File Validation**: System checks file integrity before processing #### Post-Restore Behavior - **Automatic Sign-Out**: You'll be logged out after restore begins - **Complete Replacement**: All existing data is replaced with backup data - **Service Restart**: Server may require restart to complete restoration - **Re-Authentication**: You'll need to log in with restored user credentials --- ## Start Page Settings The Start Page Settings feature allows users to customize which page they land on immediately after logging into Pinepods. This personalization option helps users streamline their workflow by starting directly on their most frequently used page. ## Overview Instead of always landing on the default home page after login, users can choose to start on any of the main Pinepods pages. This setting is saved to your user profile and syncs across all devices and platforms where you use Pinepods. ## Accessing Start Page Settings 1. Navigate to **Settings** in the main menu 2. Expand the **Start Page Settings** section 3. All users can modify their personal start page preference ## Available Start Page Options ### Main Pages You can set any of these pages as your start page: - **Home**: The default dashboard with overview information - **Feed**: Your main podcast episode feed with latest episodes - **Search**: The podcast search interface for discovering new content - **Queue**: Your episode queue for planned listening - **Saved**: Your saved/bookmarked episodes - **Downloads**: Your downloaded episodes for offline listening - **People Subscriptions**: Episodes from people you follow - **Podcasts**: Your podcast subscription library ## How to Change Your Start Page ### Step-by-Step Process 1. Open the **Start Page Settings** section 2. Wait for the current setting to load (loading spinner will disappear) 3. Click the dropdown menu to see all available page options 4. Select your preferred start page from the list 5. Click **Apply** or **Save** to confirm your choice 6. The change takes effect on your next login ### Immediate Application - Changes are saved both locally and to your user profile - New start page applies immediately to future login sessions - Setting syncs across all your Pinepods applications ## Cross-Platform Synchronization ### Device Sync Your start page preference is synchronized across: - Web browser interface - Desktop applications ### Profile Integration - Setting is tied to your user account, not device-specific - Logging in from any new device will use your saved preference - Changes made on one device immediately affect all others --- ## Custom Feed Addition The Custom Feed feature in Pinepods allows users to manually add podcast feeds that may not be available in standard podcast directories like The Podcast Index or iTunes. This is particularly useful for premium podcasts, private feeds, or independent creators who aren't indexed by major discovery services. ## Overview Custom feeds enable you to subscribe to any podcast with a valid RSS feed URL, regardless of whether it's publicly indexed. This feature supports both public feeds and premium/protected feeds that require authentication credentials. ## Accessing Custom Feed Addition 1. Navigate to **Settings** in the main menu 2. Expand the **Custom Feed** or **Add Feed** section 3. All users can add custom feeds to their personal podcast library ## How to Add Custom Feeds ### Basic Feed Addition For publicly accessible podcast feeds: #### Step-by-Step Process 1. Locate the **Add Feed** section in settings 2. Enter the podcast's RSS feed URL in the **Feed URL** field - Example: `https://bestpodcast.com/feed.xml` 3. Leave Username and Password fields empty for public feeds 4. Click **Add Feed** to subscribe to the podcast 5. Wait for confirmation that the podcast was successfully added ### Premium Feed Addition For password-protected or premium podcast feeds: #### Required Information - **Feed URL**: The RSS feed URL provided by the podcast creator - **Username**: Authentication username (if required) - **Password**: Authentication password (if required) #### Step-by-Step Process 1. Enter the premium feed's RSS URL in the **Feed URL** field 2. Enter your **Username** in the username field 3. Enter your **Password** in the password field 4. Click **Add Feed** to subscribe with authentication 5. The system will validate your credentials and add the podcast --- ## OPML Import and Export Pinepods provides comprehensive OPML (Outline Processor Markup Language) import and export functionality, allowing users to transfer their podcast subscriptions to and from other podcast applications. This feature is essential for migrating between podcast apps, creating backups, and sharing subscription lists. ## Overview OPML is the standard format used by podcast applications to exchange subscription data. Pinepods supports both importing OPML files from other podcast clients and exporting your current subscriptions to OPML format for use elsewhere. ## Accessing Import/Export Features 1. Navigate to **Settings** in the main menu 2. Look for the **Import Options** and **Export Options** sections 3. All users can import and export their personal podcast subscriptions ## Exporting Your Podcasts ### OPML Export Process The export feature creates an OPML file containing all your current podcast subscriptions. #### Step-by-Step Export 1. Locate the **Export Options** section in settings 2. Click the **Download/Export OPML** button 3. The system will generate your OPML file automatically 4. A file named `podcasts.opml` will be downloaded to your device 5. The file contains all your current podcast subscriptions with feed URLs #### What's Included in Exports - **Podcast Titles**: Names of all subscribed podcasts - **Feed URLs**: RSS feed addresses for each podcast - **Subscription Data**: Current subscription information - **Standard Format**: Compatible with most podcast applications #### Export Use Cases - **App Migration**: Moving to a different podcast application - **Backup Creation**: Preserving your subscription list - **Device Transfer**: Setting up podcasts on a new device - **Sharing**: Providing your subscription list to friends or colleagues - **Cross-Platform**: Using subscriptions on multiple podcast apps ## Importing Podcasts ### OPML Import Process The import feature allows you to add podcasts from OPML files created by other podcast applications or exported from Pinepods. #### Step-by-Step Import 1. Locate the **Import Options** section in settings 2. Click **Choose File** or browse button to select your OPML file 3. The system will parse the OPML file and display found podcasts 4. Review the list of podcasts to be imported 5. Select/deselect individual podcasts as desired (all are selected by default) 6. Click **Confirm Import** to begin the import process 7. Monitor the progress bar as podcasts are added to your library #### Import Process Features - **File Validation**: System checks OPML file format and content - **Selective Import**: Choose which podcasts to import from the file - **Progress Tracking**: Real-time progress updates during import - **Duplicate Handling**: System manages already-subscribed podcasts ### Import Progress Monitoring During import, you'll see: - **Progress Bar**: Visual indicator of import completion - **Current Podcast**: Name of the podcast currently being processed - **Total Count**: Number of podcasts being imported - **Status Updates**: Real-time feedback on the import process --- ## Playback Settings The Playback Settings section allows users to customize their podcast listening experience by configuring default playback behavior and automatic episode completion preferences. ## Accessing Playback Settings 1. Navigate to **Settings** in the main menu 2. Expand the **Playback Settings** section in the settings accordion 3. All users can access and modify their personal playback preferences ## Available Settings ### Default Playback Speed Control the default speed at which your podcasts play when you start a new episode. #### Configuration Options - **Speed Range**: 0.5x to 3.0x normal speed - **Increment**: Adjustable in 0.1x increments - **Default Value**: 1.0x (normal speed) #### How to Set Default Playback Speed 1. Locate the **Default Playback Speed** field 2. Enter your preferred speed value (e.g., 1.2 for 20% faster) 3. Use the number input field or type directly 4. Click the **Save** button (floppy disk icon) to apply changes 5. Look for the success confirmation message #### Common Speed Settings - **0.5x**: Half speed - useful for complex technical content - **0.8x**: Slower - good for dense educational material - **1.0x**: Normal speed - standard playback rate - **1.2x**: 20% faster - popular for general podcast listening - **1.5x**: 50% faster - efficient for familiar content - **2.0x**: Double speed - very fast, for experienced listeners - **3.0x**: Maximum speed - ultra-fast playback ### Auto Complete Episode Threshold Configure when episodes are automatically marked as "completed" based on how close you are to the end. #### How Auto Complete Works The system automatically marks an episode as completed when you reach within a certain number of seconds from the end. This prevents you from having to manually mark episodes as finished when there are just credits or brief outros remaining. #### Configuration Options - **Range**: 0 to 3600 seconds (0 to 1 hour) - **Default**: Varies by installation - **Increment**: 1-second adjustments #### Setting Up Auto Complete 1. Find the **Auto Complete Episode Threshold** field 2. Enter the number of seconds from the end when episodes should auto-complete 3. Click the **Save** button to apply the setting 4. The system will confirm when the change is saved --- ## Multi-Factor Authentication (MFA) Setup Pinepods provides robust Multi-Factor Authentication using Time-based One-Time Passwords (TOTP) to add an extra layer of security to user accounts. This feature works with popular authenticator apps and significantly enhances account protection. ## Overview MFA in Pinepods uses the TOTP standard (RFC 6238) with the following specifications: - **Algorithm**: SHA1 - **Digits**: 6-digit codes - **Time Window**: 30-second intervals - **Standard**: Compatible with Google Authenticator, Authy, and other TOTP apps ## Accessing MFA Settings 1. Navigate to **Settings** in the main menu 2. Expand the **MFA Settings** or **Multi-Factor Authentication** section 3. All users can enable MFA for their own accounts ## Setting Up MFA ### Prerequisites Before setting up MFA, ensure you have: - **Authenticator App**: Google Authenticator, Authy, Microsoft Authenticator, or similar - **Device Access**: The device where your authenticator app is installed - **Account Access**: Ability to log into your Pinepods account ### Step-by-Step MFA Setup #### Step 1: Initiate MFA Setup 1. In the MFA Settings section, look for the setup button 2. Click **Enable MFA** 3. The system will generate a unique secret key for your account #### Step 2: Scan QR Code 1. A QR code will appear on your screen 2. Open your authenticator app on your mobile device 3. Use the app's "Add Account" or "Scan QR Code" feature 4. Point your device's camera at the QR code displayed in Pinepods 5. The authenticator app will automatically add your Pinepods account #### Step 3: Verify Setup 1. After scanning, your authenticator app will begin generating 6-digit codes 2. Enter the current 6-digit code from your authenticator app into Pinepods 3. Click **Verify** or **Confirm** to complete the setup 4. If verification succeeds, MFA is now enabled for your account ### Manual Setup Alternative If you cannot scan the QR code: 1. Look for the text-based secret 2. In your authenticator app, choose "Enter Key Manually" 3. Add the following information: - **Account**: Your Pinepods username or "Pinepods" - **Secret Key**: Copy the displayed secret key exactly - **Time-based**: Ensure this option is selected (30-second intervals) ## Using MFA After Setup ### Login Process with MFA Enabled Once MFA is enabled, your login process changes: 1. **Standard Login**: Enter your username and password as usual 2. **MFA Prompt**: After successful password verification, you'll see an MFA code request 3. **Authenticator Code**: Open your authenticator app and find the 6-digit code for Pinepods 4. **Code Entry**: Enter the current code (codes expire every 30 seconds) 5. **Complete Login**: Click submit to complete the authentication process ### MFA Code Timing - **30-Second Window**: Each code is valid for 30 seconds - **Auto-Refresh**: Codes automatically change every 30 seconds - **Timing Indicator**: Most authenticator apps show remaining time for each code - **Clock Sync**: Ensure your device's clock is accurate for proper code generation --- ## Theme Options Pinepods offers a comprehensive theme system that allows users to customize the visual appearance of their podcast listening experience. With over 20 different themes to choose from, users can personalize their interface to match their preferences and viewing conditions. ## How to Change Themes ### Step-by-Step Process 1. Open the **Theme Settings** section 2. Click the dropdown menu to see all available themes 3. Select your preferred theme from the list 4. Click the **Apply Theme** button 5. The theme will change immediately across your interface ### Immediate Application - Theme changes take effect instantly when applied - No page refresh or restart required - All interface elements update to match the new theme ## Theme Synchronization ### Cross-Device Sync - Your theme preference is saved to your user account - Changes sync across all your Pinepods applications - Desktop, web, and mobile apps will use the same theme ### Persistent Storage - Theme choice is saved both locally and on the server - Settings persist even if you clear your browser data - Theme preference is maintained across login sessions --- ## User Self-Service Settings The User Self-Service Settings feature in Pinepods allows administrators to enable user self-registration, empowering new users to create their own accounts directly from the login screen without requiring administrator intervention. ## Administrative Configuration ### Enabling User Self-Service Registration **For Administrators Only** The User Self-Service Settings control whether users can register their own accounts through the login interface. #### Accessing Self-Service Controls 1. Navigate to **Settings** in the main menu 2. Expand the **User Settings** section 3. Locate the **User Self Service Settings** section 4. Toggle the **Enable User Self Service** switch #### How It Works When enabled, this feature: - Adds a **"Create New User"** button to the login screen - Allows new users to register accounts independently - Provides a modal registration form accessible to anyone - Validates user input according to system requirements When disabled: - Only administrators can create new user accounts - The registration button is hidden from the login screen - User creation must be done through the administrative User Settings interface #### Important Prerequisites **Highly Recommended Setup Before Enabling:** 1. **Configure Email Settings**: Essential for password reset functionality - Set up SMTP server configuration - Test email delivery to ensure users can reset forgotten passwords - Configure proper email templates and sender information 2. **Disable Server Downloads**: Prevent storage abuse by new users - Navigate to Download Settings - Disable server-side podcast downloads for security - This prevents users from consuming excessive storage space #### Security Considerations **Account Management** - New accounts are created with standard user privileges (non-admin) - Administrators should regularly review newly created accounts **Email Dependency** - Password reset functionality becomes critical with self-service enabled - Users cannot reset passwords without functional email settings - Ensure email configuration is tested and reliable --- ## API Key Management Pinepods provides comprehensive API key management functionality that allows users to create, view, and manage API keys for external integrations and programmatic access to their podcast data. This system supports secure authentication for third-party applications and custom integrations. ## Overview API keys in Pinepods enable secure, programmatic access to your podcast data and functionality. The system provides different levels of access based on user permissions and supports both individual user keys and administrative access patterns. ## Accessing API Key Management 1. Navigate to **Settings** in the main menu 2. Expand the **API Keys** section 3. User access depends on privileges: - **Standard Users**: Can view and manage only their own API keys - **Administrators**: Can view and manage all API keys across the system ## Creating API Keys ### Step-by-Step API Key Creation 1. **Navigate to API Keys**: Open the API Keys section in settings 2. **Create New Key**: Click the **Create API Key** or **Generate New Key** button 3. **Key Generation**: The system will generate a unique, secure API key 4. **Key Display**: A modal will show your new API key 5. **Save Immediately**: Copy and save the key in a secure location 6. **One-Time Display**: The key is shown only once for security reasons ### API Key Security Features - **Unique Generation**: Each key is cryptographically unique - **One-Time Display**: Keys are shown only during creation - **Secure Storage**: Keys are hashed and stored securely on the server - **Immediate Access**: Keys are active immediately after creation ### Administrative View vs User View **Standard Users See:** - Only their own API keys - Basic key information and management options - Create and delete capabilities for personal keys **Administrators See:** - All API keys across the entire system - User ownership information for each key - Enhanced management capabilities - System-wide key oversight ## Deleting API Keys ### Step-by-Step Key Deletion 1. **Select Key**: Click on the API key you want to delete 2. **Confirm Deletion**: A confirmation modal will appear 3. **Warning Review**: Review the permanent deletion warning 4. **Confirm Action**: Click **Delete** to permanently remove the key 5. **Immediate Effect**: The key becomes invalid immediately ### Deletion Considerations - **Permanent Action**: Deleted keys cannot be recovered - **Immediate Invalidation**: Applications using the key will lose access instantly - **No Reversal**: You must create a new key if access is needed again - **Planning Required**: Ensure dependent applications have alternative access ## API Key Use Cases ### External Integrations **Podcast Applications** - Mobile app synchronization - Desktop client authentication - Web application access - Cross-platform data sharing **Automation Tools** - Podcast download automation - Playlist management scripts - Episode tracking systems - Custom notification systems **Development Projects** - Custom podcast clients - Integration with other services - Data analysis tools - Backup and sync utilities ### Third-Party Services (In the future I hope these exist) **Media Centers** - Plex integration - Kodi plugin access - Home automation systems - Smart speaker integration **Productivity Tools** - Calendar integration for episode releases - Task management system connections - Note-taking application sync - Personal dashboard widgets --- ## Browsing Podcasts in Pinepods Pinepods provides a comprehensive interface for browsing and managing your podcast content across multiple organized views. Each page is designed to help you navigate your podcast library efficiently and find the content you want to listen to. ## Overview of Browsing Pages Pinepods organizes your podcast content into five main browsing areas, each serving a specific purpose in your podcast listening workflow: - **Feed**: Your personalized episode feed with the latest content - **Podcasts**: Library view of all your subscribed podcasts - **Queue**: Episodes you've queued up for listening - **Saved**: Episodes you've bookmarked for later - **Server Downloads**: Episodes downloaded to the server for archival ## Feed Page ### Purpose The Feed page serves as your main content discovery hub, displaying the most recent episodes from all your subscribed podcasts in chronological order from the last 30 days. ### Content Display - **Recent Episodes**: Shows newest episodes across all subscriptions - **Mixed Content**: Combines episodes from all your podcasts in one timeline - **Publication Order**: Episodes are sorted by their original publication date ### Navigation Tips - Use the Feed page as your starting point for discovering new content - Scroll through to find older episodes you might have missed - Use episode actions to organize content for later listening ## Podcasts Page ### Purpose The Podcasts page provides a library view of all your subscribed podcasts, allowing you to browse by show rather than by episode. ### Display Options - **Grid Layout**: Visual grid showing podcast artwork and titles - **List Layout**: Compact list view with podcast details - **Podcast Information**: Title and description - **Episode Counts**: See how many episodes are available for each podcast ### Management Features - **Podcast Removal**: Unsubscribe from podcasts you no longer want - **Search and Filter**: Find specific podcasts in your library - **Organization Tools**: Sort and categorize your podcast subscriptions ### Podcast Interaction - **Episode Access**: Click any podcast to see all its episodes - **Subscription Management**: Add or remove podcast subscriptions - **Artwork Display**: Visual browsing using podcast cover art - **Quick Actions**: Access podcast-specific settings and options ## Queue Page ### Purpose The Queue page displays episodes you've explicitly added to your listening queue, providing a personalized playlist for planned listening. ### Queue Management - **Episode Order**: Drag and drop to reorder episodes in your queue - **Playback Sequence**: Episodes play in the order you've arranged them - **Queue Status**: See your current position in the queue - **Bulk Actions**: Manage multiple episodes at once ### Queue Features - **Touch Gestures**: Long press on mobile for additional options - **Auto-Scroll**: Smart scrolling during drag operations - **Visual Feedback**: Clear indicators for drag and drop operations - **Queue Length**: See total listening time for your entire queue ### Queue Workflow 1. **Add Episodes**: Queue episodes from any other page in Pinepods 2. **Organize Order**: Arrange episodes in your preferred listening sequence 3. **Start Playback**: Begin playing from any point in your queue 4. **Auto-Advance**: Episodes automatically progress through your queue 5. **Dynamic Updates**: Add or remove episodes while listening ## Saved Page ### Purpose The Saved page contains episodes you've bookmarked for future listening, serving as your personal favorites collection. ### Content Organization - **Saved Episodes**: All episodes you've marked as saved - **Search Functionality**: Find specific saved episodes quickly - **Sorting Options**: Multiple ways to organize your saved content - **Filter Controls**: Narrow down saved episodes by various criteria ### Sorting Options - **Newest First**: Most recently saved episodes at the top - **Oldest First**: Show chronologically oldest saved episodes first - **Shortest First**: Sort by episode duration, shortest episodes first - **Longest First**: Sort by episode duration, longest episodes first - **Title A-Z**: Alphabetical sorting by episode title - **Title Z-A**: Reverse alphabetical sorting by episode title ### Saved Episode Management - **Remove from Saved**: Unsave episodes you no longer need bookmarked - **Episode Details**: Access full episode information and show notes - **Playback Integration**: Play saved episodes directly from the saved list - **Status Indicators**: See completion and listening progress for saved episodes ## Server Downloads Page ### Purpose The Server Downloads page shows episodes that have been downloaded to the Pinepods server for offline access and improved performance. ### Download Features - **Faster Loading**: Downloaded episodes load more quickly - **Server Storage/Archival**: Files stored on your Pinepods server - **Bandwidth Savings**: Reduced external bandwidth usage for repeated listening ### Download Management - **Download Status**: See which episodes are downloaded vs. streaming - **Storage Information**: View file sizes and storage usage - **Bulk Operations**: Download or delete multiple episodes at once - **Episode Grouping**: Episodes organized by podcast for easy management ### Download Organization - **Podcast Grouping**: Episodes grouped by their parent podcast - **Search and Filter**: Find specific downloaded content - **Completion Status**: Track listening progress for downloaded episodes ## Universal Features Across All Pages ### Navigation Elements - **Search Bar**: Top-right search functionality available on all pages - **App Drawer**: Side navigation menu for quick page switching - **Audio Player**: Persistent audio controls at the bottom of all pages ### Episode Actions Available on all browsing pages: - **Play/Pause**: Start or stop episode playback - **Save/Unsave**: Bookmark episodes for later - **Queue/Unqueue**: Add or remove episodes from your listening queue - **Download**: Save episodes to server storage - **Show Notes**: Access detailed episode information ### Visual Indicators Consistent across all pages: - **Completion Status**: Visual indicators for completed episodes - **Progress Bars**: Show partial listening progress ### Responsive Design - **Mobile Optimization**: Touch-friendly interfaces on all pages - **Desktop Enhancement**: Hover states and larger click targets on desktop - **Adaptive Layouts**: Content adjusts to different screen sizes - **Gesture Support**: Swipe and touch gestures on mobile devices ## Integration with Audio Player ### Seamless Playback - **Universal Controls**: Audio player works consistently across all browsing pages - **Context Preservation**: Navigate between pages without interrupting playback - **Queue Integration**: Playing episodes automatically updates your queue status - **Progress Sync**: Listening progress syncs across all pages and devices ### Smart Features - **Resume Playback**: Return to exact playback position when switching pages - **Background Play**: Continue listening while browsing other content - **Cross-Page Actions**: Episode actions work regardless of which page you're viewing --- ## Using Clients in Pinepods [![Discord](https://img.shields.io/badge/discord-join%20chat-5B5EA6)](https://discord.gg/bKzHRa4GNc) [![Chat on Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#pinepods:matrix.org) [![Docker Container Build](https://github.com/madeofpendletonwool/PinePods/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/madeofpendletonwool/PinePods/actions) [![GitHub Release](https://img.shields.io/github/v/release/madeofpendletonwool/pinepods)](https://github.com/madeofpendletonwool/PinePods/releases) *Client* in Pinepods refers to an external app that connects to your Pinepods server. The server being hosted via Docker and the client installed generally as an app on your device locally. In fact when you setup Pinepods via docker it technically comes pre-setup with a client. Which is the web version. This page is details on installing clients besides the web version should you choose to. (The mobile apps are HIGHLY recommended if you listen to podcasts on the go) There's client versions of Pinepods for Linux (Deb, Appimage, Flatpak, AUR, and RPM), Mac, Windows, Android, and iOS. Scroll down for install instructions. ### Linux Client Install :computer: The Pinepods Linux client is available through multiple distribution methods. Choose the method that works best for your Linux distribution. #### Quick Install (Recommended) **Flatpak - Universal Linux Package** Flatpak works on all major Linux distributions and provides automatic updates. ```bash # Install Flatpak if not already available sudo apt install flatpak # Debian/Ubuntu sudo dnf install flatpak # Fedora sudo pacman -S flatpak # Arch Linux sudo zypper install flatpak # openSUSE # Add Flathub repository (if not already added) flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo # Install Pinepods flatpak install flathub com.gooseberrydevelopment.pinepods # Run Pinepods flatpak run com.gooseberrydevelopment.pinepods ``` 🔗 **Available at:** https://flathub.org/apps/com.gooseberrydevelopment.pinepods --- #### Distribution-Specific Installation **Arch Linux & Arch-based Distros** Install from the AUR (Arch User Repository): ```bash # Using yay yay -S pinepods # Using paru paru -S pinepods # Using makepkg (manual) git clone https://aur.archlinux.org/pinepods.git cd pinepods makepkg -si ``` 🔗 **AUR Package:** https://aur.archlinux.org/packages/pinepods **Debian & Ubuntu** Download and install the DEB package: Download the latest deb [here](https://github.com/madeofpendletonwool/PinePods/releases) ```bash # Install the package sudo dpkg -i pinepods_amd64.deb # Fix any dependency issues (if needed) sudo apt-get install -f # Run Pinepods pinepods ``` **Fedora, CentOS, RHEL & openSUSE** Download and install the RPM package: Download the latest rpm [here](https://github.com/madeofpendletonwool/PinePods/releases) ```bash sudo dnf install ./pinepods.rpm # openSUSE wget https://github.com/madeofpendletonwool/PinePods/releases/latest/download/pinepods.rpm sudo zypper install ./pinepods.rpm # Run Pinepods pinepods ``` **Linux Mint** Linux Mint supports both DEB packages and Flatpak: Download the latest deb [here](https://github.com/madeofpendletonwool/PinePods/releases) ```bash # Option 1: DEB package (recommended for Mint) sudo dpkg -i pinepods_amd64.deb sudo apt-get install -f # Option 2: Flatpak flatpak install flathub com.gooseberrydevelopment.pinepods ``` **Elementary OS** Elementary OS has excellent Flatpak integration: ```bash # Install via AppCenter (search for "Pinepods") or terminal: flatpak install flathub com.gooseberrydevelopment.pinepods ``` **Pop!_OS** Pop!_OS supports both DEB and Flatpak: Download the latest deb [here](https://github.com/madeofpendletonwool/PinePods/releases) ```bash sudo dpkg -i pinepods_amd64.deb # Or via Pop!_Shop (search for "Pinepods") flatpak install flathub com.gooseberrydevelopment.pinepods ``` **Manjaro Linux** Manjaro supports AUR packages by default: ```bash # Using pamac (Manjaro's package manager) pamac install pinepods # Or using yay yay -S pinepods ``` --- #### Universal Methods **AppImage - Portable Application** Perfect for any Linux distribution or when you don't have admin privileges: Download the latest appimage [here](https://github.com/madeofpendletonwool/PinePods/releases) ```bash # Make it executable chmod +x pinepods.appimage # Run it ./pinepods.appimage # Optional: Integrate with system (creates desktop entry) ./pinepods.appimage --appimage-extract-and-run --appimage-integrate ``` **Manual Download Options** Visit the releases page for all available formats: 🔗 **GitHub Releases:** https://github.com/madeofpendletonwool/PinePods/releases --- #### Post-Installation Setup Once installed through any method: 1. **Launch Pinepods** from your application menu or terminal 2. **Enter your server details:** - **Server URL:** The web address where your Pinepods server is hosted (e.g., `https://pinepods.example.com`) - **Username:** Your Pinepods username - **Password:** Your Pinepods password 3. **Sign in** and start enjoying your podcasts! ### Windows Client Install :computer: Any of the client additions are super easy to get going. First head over to the releases page on Github https://github.com/madeofpendletonwool/PinePods/releases There's a exe and msi windows install file. The exe will actually start an install window and allow you to properly install the program to your computer. The msi will simply run a portable version of the app. Either one does the same thing ultimately and will work just fine. Once started you'll be able to sign in with your username and password. The server name is simply the url you browse to to access the server. ### Mac Client Install :computer: Any of the client additions are super easy to get going. First head over to the releases page on Github https://github.com/madeofpendletonwool/PinePods/releases There's a dmg and pinepods_mac file. Simply extract, and then go into Contents/MacOS. From there you can run the app. The dmg file will prompt you to install the Pinepods client into your applications folder while the _mac file will just run a portable version of the app. Once started you'll be able to sign in with your username and password. The server name is simply the url you browse to to access the server. ### Android Install :iphone: The native Android app is available now, with Android Auto support! - ▶️ [Google Play Store](https://play.google.com/store/apps/details?id=com.gooseberrydevelopment.pinepods) — the easiest way to install and stay updated - 📱 [IzzyOnDroid](https://apt.izzysoft.de/fdroid/index/apk/com.gooseberrydevelopment.pinepods) — install and update through the IzzyOnDroid F-Droid repo - 🔄 [Obtainium](https://github.com/madeofpendletonwool/PinePods/releases) — track GitHub Releases for automatic updates - 📦 Direct APK from [GitHub Releases](https://github.com/madeofpendletonwool/PinePods/releases) ### iOS Install :iphone: The native iOS app is on the [App Store](https://apps.apple.com/us/app/pinepods/id6751441116), with CarPlay support! Search for "Pinepods" in the App Store or use the link above to install. ### Firewood (CLI TUI player) **Pinepods Firewood** is now available! It's a beautiful terminal-based client for power users who prefer command-line interfaces. **Installation:** 1. **Download from GitHub** - Visit the [Pinepods Firewood repository](https://github.com/madeofpendletonwool/pinepods-firewood) - Download the latest release for your platform - Follow the installation instructions in the repository 2. **Features:** - Beautiful terminal user interface (TUI) - Full podcast management capabilities - Lightweight and fast - Perfect for remote servers and headless systems See the **Firewood** section in the documentation sidebar for detailed installation and usage instructions. #### Troubleshooting **Getting Help:** - 📚 Check our **Troubleshooting** section in the docs sidebar - 💬 Join our [Discord community](https://discord.com/invite/bKzHRa4GNc) - 🐛 Report issues on [GitHub](https://github.com/madeofpendletonwool/PinePods/issues) --- ## PinePods Environment Variables Guide Complete reference for all PinePods configuration options Below are all the environment variables supported by PinePods. These should be configured in your `docker-compose.yml` file or `.env` file. ## Core Application Settings | Variable | Default Value | Required | Description | |----------|---------------|----------|-------------| | `SEARCH_API_URL` | `https://search.pinepods.online/api/search` | **Yes** | External URL for the search API that the frontend can access. Set this to your domain + port (e.g., `https://yourdomain.com:8000`) | | `PEOPLE_API_URL` | `https://people.pinepods.online` | **Yes** | External URL for the people/person lookup API | | `HOSTNAME` | `http://localhost:8040` | **Yes** | The URL where you will access the app. Used for RSS feed sharing and callbacks | | `SERVER_URL` | (falls back to `HOSTNAME`) | **No** | Explicit public URL for building absolute RSS feed links. Checked before `HOSTNAME`; set it if your container platform overrides `HOSTNAME` (see note below) | :::tip RSS links showing your container name instead of your domain? PinePods builds absolute RSS feed URLs (``, ``, ``) from `HOSTNAME`. Some container runtimes — rootless Podman under a systemd unit is a known case — set their own `HOSTNAME` (the container/pod name), which can override the value you passed in. If your feed's episode links look like `pinepods-pod/api/data/stream/...` instead of your real domain, set `SERVER_URL` to your public URL (the same value you'd give `HOSTNAME`). PinePods checks `SERVER_URL` first, and unlike `HOSTNAME`, nothing in the container platform can silently overwrite it. ::: ## Database Configuration | Variable | Default Value | Required | Description | |----------|---------------|----------|-------------| | `DB_TYPE` | `postgresql` | **Yes** | Database type: `postgresql` or `mariadb` | | `DB_HOST` | `localhost` | **Yes** | Database host address | | `DB_PORT` | `5432` (PostgreSQL) / `3306` (MariaDB) | **Yes** | Database port | | `DB_USER` | `postgres` (PostgreSQL) / `root` (MariaDB) | **Yes** | Database username | | `DB_PASSWORD` | - | **Yes** | Database password (required) | | `DB_NAME` | `pinepods_database` | **Yes** | Database name | ## Redis/Valkey Configuration | Variable | Default Value | Required | Description | |----------|---------------|----------|-------------| | `VALKEY_HOST` | `valkey` | **Yes** | Valkey/Redis host for caching and sessions | | `VALKEY_PORT` | `6379` | **Yes** | Valkey/Redis port | | `VALKEY_PASSWORD` | `ValkeySecurePassword123!` | **No** | Valkey/Redis Password if it's setup. Only required with external custom valkey servers | ## OIDC (OpenID Connect) Configuration All OIDC variables are optional but must be configured together if using OIDC authentication. | Variable | Default Value | Required | Description | |----------|---------------|----------|-------------| | `OIDC_PROVIDER_NAME` | - | OIDC Setup | Display name for the OIDC provider | | `OIDC_CLIENT_ID` | - | OIDC Setup | OIDC client ID from your provider | | `OIDC_CLIENT_SECRET` | - | OIDC Setup | OIDC client secret from your provider | | `OIDC_AUTHORIZATION_URL` | - | OIDC Setup | OIDC authorization endpoint URL | | `OIDC_TOKEN_URL` | - | OIDC Setup | OIDC token endpoint URL | | `OIDC_USER_INFO_URL` | - | OIDC Setup | OIDC user info endpoint URL | | `OIDC_BUTTON_TEXT` | `Login with OIDC` | No | Text displayed on the OIDC login button | | `OIDC_SCOPE` | `openid email profile` | No | Space-separated list of OIDC scopes | | `OIDC_BUTTON_COLOR` | `#000000` | No | Background color of the OIDC login button | | `OIDC_BUTTON_TEXT_COLOR` | `#FFFFFF` | No | Text color of the OIDC login button | | `OIDC_ICON_SVG` | - | No | SVG icon code for the OIDC button | | `OIDC_NAME_CLAIM` | - | No | OIDC claim field for user's display name | | `OIDC_EMAIL_CLAIM` | - | No | OIDC claim field for user's email | | `OIDC_USERNAME_CLAIM` | - | No | OIDC claim field for username | | `OIDC_ROLES_CLAIM` | - | No | OIDC claim field for user roles | | `OIDC_USER_ROLE` | - | No | Role value that grants regular user access | | `OIDC_ADMIN_ROLE` | - | No | Role value that grants administrator access | | `OIDC_DISABLE_STANDARD_LOGIN` | `false` | No | Set to `true` to disable username/password login entirely | ## Initial Admin Account Setup | Variable | Default Value | Required | Description | |----------|---------------|----------|-------------| | `USERNAME` | - | No | Initial admin username (optional, prompts on first boot if not set) | | `PASSWORD` | - | No | Initial admin password (optional, prompts on first boot if not set) | | `FULLNAME` | - | No | Initial admin full name | | `EMAIL` | - | No | Initial admin email address | ## Logging & Debugging | Variable | Default Value | Required | Description | |----------|---------------|----------|-------------| | `DEBUG_MODE` | `false` | No | Enable debug logging and features | | `RUST_LOG` | - | No | Rust-specific logging level | ## Container & System Settings | Variable | Default Value | Required | Description | |----------|---------------|----------|-------------| | `PUID` | `1000` | No | User ID for file permissions | | `PGID` | `1000` | No | Group ID for file permissions | ## Quick Setup Guides ### Essential Variables for Any Setup ```yaml # Database (required) DB_TYPE: postgresql # or mariadb DB_HOST: db DB_PORT: 5432 # or 3306 for MariaDB DB_USER: postgres # or root for MariaDB DB_PASSWORD: "your_secure_password" DB_NAME: pinepods_database # Valkey/Redis (required) VALKEY_HOST: valkey VALKEY_PORT: 6379 # External APIs (required) SEARCH_API_URL: "https://yourdomain.com:8000/api/search" PEOPLE_API_URL: "https://people.pinepods.online" HOSTNAME: "https://yourdomain.com:8040" ``` ### Complete OIDC Setup Example ```yaml # Basic OIDC Configuration OIDC_PROVIDER_NAME: "My Company SSO" OIDC_CLIENT_ID: "your-client-id" OIDC_CLIENT_SECRET: "your-client-secret" OIDC_AUTHORIZATION_URL: "https://auth.company.com/oauth2/authorize" OIDC_TOKEN_URL: "https://auth.company.com/oauth2/token" OIDC_USER_INFO_URL: "https://auth.company.com/oauth2/userinfo" # Optional OIDC Customization OIDC_BUTTON_TEXT: "Login with Company SSO" OIDC_SCOPE: "openid email profile groups" OIDC_BUTTON_COLOR: "#1a365d" OIDC_BUTTON_TEXT_COLOR: "#ffffff" # Role Mapping OIDC_ROLES_CLAIM: "groups" OIDC_USER_ROLE: "pinepods-users" OIDC_ADMIN_ROLE: "pinepods-admins" # Disable standard login (optional) OIDC_DISABLE_STANDARD_LOGIN: true ``` --- ## Legend - **Yes**: Required for basic functionality - **OIDC Setup**: Required if using OIDC authentication - **Email Setup**: Required if using email features - **No**: Optional enhancement% --- ## Searching and Adding Podcasts Pinepods provides powerful podcast discovery tools that allow you to search across multiple podcast directories and add new shows to your subscription library. The search system integrates with major podcast indexes to help you find both popular and niche content. ## Overview Pinepods supports podcast search through three major platforms: - **Podcast Index**: Community-driven, open podcast directory with comprehensive coverage - **iTunes**: Apple's extensive podcast catalog with mainstream and indie content - **Youtube**: Add youtube channels as audio only podcasts The search interface is accessible from the top-right corner of every page in Pinepods and provides a unified way to discover and subscribe to new podcasts. ## Accessing Search ### Search Bar Location The search functionality is available via the search bar located in the top-right corner of the Pinepods interface: 1. **Desktop**: Search bar is prominently displayed in the top navigation 2. **Mobile**: Touch the search icon to expand the search interface 3. **All Pages**: Search remains accessible regardless of which page you're viewing ### Search Interface Components - **Search Input**: Text field for entering podcast names, topics, or keywords - **Index Selector**: Dropdown to choose between Podcast Index, iTunes and Youtube - **Search Button**: Executes the search across your selected index - **Results Display**: Shows matching podcasts with add/subscribe options --- ## The Settings Page The Settings page in Pinepods is your central hub for customizing the application to fit your preferences and managing various aspects of your podcasting experience. Located in the main navigation menu, the Settings page provides access to a comprehensive suite of configuration options organized into intuitive sections. ## Accessing the Settings Page You can access the Settings page in several ways: - Click the **Settings** option in the main navigation menu - Use the gear/cog icon in the top navigation bar - Access settings-specific options through context menus throughout the application ## Settings Organization The Settings page is organized into several main categories using an accordion-style interface: ### User Management - **User Settings**: Manage user accounts, passwords, and administrative privileges - **User Self-Service**: Allow users to manage their own account settings - **Multi-Factor Authentication (MFA)**: Set up additional security layers for user accounts ### Appearance & Behavior - **Theme Options**: Customize the visual appearance with light, dark, and custom themes - **Playback Settings**: Configure default playback speeds and auto-completion settings - **Start Page Options**: Set your preferred landing page when opening Pinepods ### Content Management - **Import/Export Options**: Manage podcast subscriptions and user data - **Custom Feeds**: Create and manage custom RSS feeds - **Backup & Restore**: Protect your data with backup and restore functionality ### Integration & Communication - **API Keys**: Manage authentication keys for external integrations - **Email Settings**: Configure email notifications and communication - **OIDC Settings**: Set up single sign-on with OpenID Connect providers - **Notification Settings**: Control how and when you receive notifications ### Data Management - **Download Settings**: Configure automatic downloads and storage preferences - **RSS Feed Management**: Manage external RSS feed integrations - **Guest Settings**: Control access and permissions for guest users ## Navigation Tips - Each settings section uses an expandable accordion interface - click on section headers to expand or collapse them - Changes are typically saved automatically or with prominent save buttons - Administrative settings are only visible to users with admin privileges - Some settings may require application restart to take full effect ## Admin vs. User Settings Pinepods distinguishes between administrative settings (server-wide configuration) and user settings (individual preferences): - **Admin Settings**: Affect all users and require administrative privileges - **User Settings**: Personal preferences that only affect the current user's experience - **Self-Service Options**: Allow users to modify their own account details without admin intervention For detailed information about specific settings sections, see the individual documentation pages for each component. --- ## Sign into Pinepods Pinepods provides a comprehensive sign-in experience that includes user authentication, customizable landing pages, and seamless integration with your preferred podcast listening workflow. The system supports multiple authentication methods and personalized start page preferences. ## Overview The Pinepods sign-in system consists of several key components: - **User Authentication**: Secure login with username and password - **Multi-Factor Authentication**: Optional TOTP-based security enhancement - **Password Reset**: Self-service password recovery via email as long as you setup email options - **Start Page Configuration**: Customizable landing page after login - **Session Management**: Persistent login sessions across devices ## Standard Login Process ### Basic Authentication #### Step 1: Enter Credentials 1. **Username**: Type your assigned or chosen username 2. **Password**: Enter your account password 3. **Verify Input**: Ensure credentials are entered correctly 4. **Submit**: Click the "Sign In" button to authenticate #### Step 2: System Verification 1. **Credential Check**: Pinepods verifies your username and password 2. **Account Status**: System confirms your account is active 3. **Authentication Success**: Successful login proceeds to your start page 4. **Error Handling**: Invalid credentials display appropriate error messages #### Step 3: Post-Login Actions 1. **Session Creation**: Pinepods establishes your user session 2. **Preferences Loading**: System loads your personal settings and preferences 3. **Start Page Navigation**: Automatic redirect to your configured start page ## Multi-Factor Authentication (MFA) ### MFA-Enhanced Login Process If you've enabled MFA on your account, the login process includes an additional security step: #### Standard Login First 1. **Username and Password**: Complete the normal credential entry 2. **Initial Verification**: Pinepods validates your basic credentials 3. **MFA Prompt**: System requests your authenticator code #### MFA Code Entry 1. **Authenticator App**: Open your TOTP authenticator app (Google Authenticator, Authy, etc.) 2. **Locate Code**: Find the 6-digit code for your Pinepods account 3. **Enter Code**: Input the current code in the MFA prompt 4. **Time Sensitivity**: Codes expire every 30 seconds, so enter promptly 5. **Complete Login**: Successful MFA verification completes the login process ### MFA Troubleshooting - **Expired Codes**: Wait for a new code if the current one has expired - **Time Sync**: Ensure your device's clock is accurate for proper code generation - **Code Accuracy**: Double-check that you're entering the code correctly - **App Issues**: Verify you're using the code from the correct account in your authenticator ## Password Recovery ### Forgot Password Process If you've forgotten your password, Pinepods provides a self-service recovery option as long as you set it up in the admin area of settings: #### Initiating Password Reset 1. **Forgot Password Link**: Click "Forgot Password?" on the login page 2. **Account Information**: Enter your username and associated email address 3. **Reset Request**: Submit the password reset request 4. **Email Verification**: Check your email for the reset code #### Completing Password Reset 1. **Email Code**: Locate the password reset code in your email 2. **Return to Interface**: The reset modal will appear after submitting the request 3. **New Password**: Enter your desired new password 4. **Reset Code**: Input the code from your email 5. **Submit Changes**: Complete the password reset process 6. **Login**: Use your new password to log into Pinepods ### Password Reset Requirements - **Valid Email**: Your account must have a valid email address configured - **Email Configuration**: Administrators must have configured email settings on the server - **Code Expiration**: Reset codes expire after a certain time for security - **Single Use**: Each reset code can only be used once ## User Self-Registration ### Self-Service Account Creation If enabled by administrators, new users can create their own accounts: #### Account Creation Process 1. **Create New User**: Click the "Create New User" button (if visible) 2. **User Information**: Provide required account details: - **Username**: Choose a unique username for your account - **Password**: Create a secure password - **Email Address**: Provide a valid email for account recovery - **Full Name**: Enter your display name 3. **Account Validation**: System verifies the provided information 4. **Account Creation**: Successful validation creates your new account #### Self-Registration Requirements - **Administrator Permission**: Feature must be enabled by server administrators - **Unique Username**: Chosen username must not already exist - **Valid Email**: Email address must be properly formatted and accessible ## Start Page Configuration ### Customizing Your Landing Page Pinepods allows you to configure which page you see immediately after logging in in the settings of your account: #### Available Start Page Options - **Home**: Dashboard view with recent activity and quick access features - **Feed**: Your personalized episode feed with latest content - **Podcasts**: Library view of all your subscribed podcasts - **Queue**: Your listening queue with planned episodes - **Saved**: Collection of bookmarked episodes - **Downloads**: Episodes downloaded to the server #### Setting Your Start Page 1. **Navigate to Settings**: Access your user settings after logging in 2. **Start Page Options**: Find the start page configuration section 3. **Select Preference**: Choose your preferred landing page 4. **Save Settings**: Apply your start page preference 5. **Next Login**: Your choice takes effect on subsequent logins ## Session Management ### Login Session Features - **Persistent Sessions**: Stay logged in across browser sessions - **Multiple Devices**: Use the same account on different devices simultaneously - **Cross-Platform**: Sessions work across web, mobile, and desktop clients ## Troubleshooting Login Issues #### Email Issues (Password Reset) - **Email Configuration**: Verify your account has the correct email address - **Spam Folder**: Check spam/junk folders for password reset emails - **Email Delivery**: Allow time for email delivery - **Administrator Help**: Contact administrators if email issues persist #### MFA Problems - **Clock Synchronization**: Ensure your device's time is accurate - **Code Generation**: Verify your authenticator app is generating codes - **Setup Verification**: Confirm MFA was set up correctly - **Recovery Options**: Contact administrators if locked out due to MFA issues ### Browser and Technical Issues #### Browser Compatibility - **Supported Browsers**: Use current versions of major browsers (Chrome, Firefox, Safari, Edge) - **JavaScript**: Ensure JavaScript is enabled in your browser - **Cookies**: Enable cookies for the Pinepods domain - **Cache Issues**: Clear browser cache if experiencing persistent problems --- ## OIDC Setup You can now setup OIDC logins in Pinepods to use either your own self-hosted OIDC provider or one of the other large cloud hosted providers such as Github, Google, or Azure. Anything that follows the OIDC standard (and also Github even though they don't follow the standard) will work just fine. Below is instructions for setting up different types of providers (NOTE: Only admins can setup OIDC Settings) ### Resources Before we get started your OIDC provider may provider the option to upload an image of Pinepods to use as the App Image. You should be able to use the one below: ![Pinepods App Image](/img/favicon.png) ### Using a self-hosted provider (Highly Recommended) Seriously, since you're already self-hosted Pinepods you might as well self-host an OIDC provider. I recommend [PocketID](https://github.com/pocket-id/pocket-id) 1. First head over to the settings page of Pinepods and open up the OIDC settings area ![OIDC Settings](/img/oidcsettings.png) 2. Now click Add Provider - On this page you'll need to fill out the options according to your provider. 3. Create a new OIDC client in your provider. Enter the callback URL that you can copy from Pinepods into the OIDC provider where it's required. Should be something like this. Do not check public client or PKCE. ![OIDC callback](/img/oidccallback.png) 4. Now your provider should give you all the options that Pinepods needs to be setup ![OIDC Options](/img/oidcoptions.png) 5. Go ahead and copy over everything from your provider into the correct fields in Pinepods (You probably won't use every option your provider gave you. That's fine, Pinepods only needs the auth token, and user info url. Along with the ID and secret) 6. At this point you should be left with the Name field, the scopes, button text, text color, button color, and svg options. Put in your provider for the name. If you use PocketID then enter PocketID 7. For the scopes, it'll be somewhat dependant on the provider. Some providers allow you to choose scopes. Pinepods by default will have openid, email, and profile enabled by default. If you use PocketID or a similar self-hosted provider this default will probably work. If you do need to change the scopes, select the dropdown and click the ones you need. 8. For the button options that's all up to you. The button text field is what the button will say to login. So maybe something like - 'Login with PocketID' 9. For the colors just choose options that are likely to look good together. You might consider using colors that match the colors of your OIDC provider. Just don't choose black text with black button or you won't be able to read it. 10. For the SVG, it's entirely optional and you can click Submit at this point, but if you can either find an SVG for your given provider or use one of the many online converters to convert the favicon of your provider into an svg you can enter it below. This may take some trial and error to get it to show up right. Additionally, you must provide the full svg wrapped in proper svg tag. For example ``` mysvgcontent ``` 11. Hit submit! Now go ahead and log out. From here you might need to refresh but you should now see the OIDC login button appear on the page for you. Go ahead and click it. It will route you outside Pinepods and then back in once you've authenticated where you'll setup your account. ![OIDC Button](/img/myoidcbutton.png) ### Using a Nextcloud as your OIDC provider (Also works great) This option is great is you already have a Nextcloud Server spun up. 1. First head over to the settings page of Pinepods and open up the OIDC settings area ![OIDC Settings](/img/oidcsettings.png) 2. Now click Add Provider - On this page you'll need to fill out the options according to your provider. 3. Install or ensure you have the Nextcloud OIDC Provider app. It's [this](https://github.com/H2CK/oidc). You should be able to search for and install this in Nextcloud ![Nextcloud OIDC](/img/nextcloud-oidc.png) 3. Create a new OIDC client in Nextcloud. Go to Admin Settings -> Security -> OpenID Connect clients. Create a new client. Call it something like 'Pinepods Login', enter the redirect URL from the Pinepods OIDC page, leave RS256 selected, and leave Confidential. 4. Copy the ID and secret and enter them into Pinepods in the respective fields. 5. Select Code Authorization Flow in the Nextcloud Flows field. 6. Limit the scope to a group you are part of. 7. Enter these options info the user info, auth, and Token URL fields of Pinepods - Authorization URL: https://YOUR-NEXTCLOUD-SERVER-URL/index.php/apps/oidc/authorize - Token URL: https://YOUR-NEXTCLOUD-SERVER-URL/index.php/apps/oidc/token - User Info URL: https://YOUR-NEXTCLOUD-SERVER-URL/index.php/apps/oidc/userinfo 6. At this point you should be left with the Name field, the scopes, button text, text color, button color, and svg options. Put Something like Nextloud into the Provider name box. 7. For the scopes, leave the default in Pinepods. Just don't change anything. 8. For the button options that's all up to you. The button text field is what the button will say to login. So maybe something like - 'Login with Nextcloud' 9. For the colors just choose options that are likely to look good together. Blue makes sense for Nextloud. You might consider using colors that match the colors of your OIDC provider. Just don't choose black text with black button or you won't be able to read it. 10. For the SVG, it's entirely optional and you can click Submit at this point. An svg for nextcloud is pretty easy to find. You must provide the full svg wrapped in proper svg tag. For example ``` mysvgcontent ``` 11. Hit submit! Now go ahead and log out. From here you might need to refresh but you should now see the OIDC login button appear on the page for you. Go ahead and click it. It will route you outside Pinepods and then back in once you've authenticated where you'll setup your account. ![OIDC Button](/img/myoidcbutton.png) ### Using Github As your OIDC Provider 1. First Follow all the steps above until you get to the OIDC provider Settings page and setup some of the initial name information. 2. Login to Github and go to the settings under your profile. You can also just [Click here and skip to step 4](https://github.com/settings/profile) 3. Then scroll to the bottom and click Developer settings. From here select 'OAuth Apps' Create a new OAuth App. 4. Create a New OAuth App. Give it a name and enter your Pinepods homepage for the homepage url, enter a description, then copy the callback url from the OIDC settings area in Pinepods and paste it into the Authorization Callback URL text box in github. So to clarify, if your Pinepods instance lives at https://try.pinepods.online. You would enter Application name: Pinepods Homepage URL: https://try.pinepods.online Application description: My Pinepods instance rocks! Authorization callback URL: https://try.pinepods.online/api/auth/callback Device Flow: false (Leave unchecked) 5. Once created copy the client id and enter it into Pinepods. Then create a secret and paste that into Pinepods as well 6. Feel free to grab the favicon from above to enter an image into Github 7. From here just enter these urls into the auth url, token url, and user info url boxes: ``` Authorization URL: https://github.com/login/oauth/authorize Token URL: https://github.com/login/oauth/access_token User Info URL: https://api.github.com/user ``` 8. You'll notice the scope auto detected Github. So leave those as is 9. Simply enter the rest based on what's written above about the customization. For svg take a look at the github icons they offer. Otherwise, the one below works pretty great! Just paste that in! ``` ``` 10. Logout and then authenticate with Github. You'll be asked to authorize the app the first time and then you'll be logged in assuming everything went right! ### Using Google As your OIDC Provider 1. First Follow all the steps above until you get to the OIDC provider Settings page and setup some of the initial name information. 2. Using a chromium based browser (GCP makes firefox explode) Head over to [The Google Cloud Console](https://console.cloud.google.com/) 3. Either Select an existing Project if you have one or make a new one 4. Click the hamburger menu and then click "APIs and Services". From here, select 'Credentials' on the left 5. Now at the top click 'Create Credentials' and then choose OAuth client ID 6. For app type, choose Web Application, and then provide a name. 7. Click add provider in the OIDC settings in Pinepods and then copy the OIDC redirect URL from Pinepods and paste it into the Authorized redirect URIs in Gsuite. Then click Create. 8. You'll be provided an ID and secret right away. Paste those into Pinepods 9. Now enter the urls for google: ``` Authorization URL: https://accounts.google.com/o/oauth2/v2/auth Token URL: https://oauth2.googleapis.com/token User Info URL: https://openidconnect.googleapis.com/v1/userinfo ``` 9. Simply enter the rest based on what's written above about the customization. For svg there's plenty of options that can be sourced online. Otherwise, the one below is a basic black Google icon. Feel free to use this. ``` ``` 10. Logout and then authenticate with Google. You'll be asked to authorize the app the first time and then you'll be logged in assuming everything went right! --- ## Password Reset System Pinepods provides a comprehensive password reset system that allows users to securely reset their passwords when they cannot access their accounts. This system consists of two main components: email configuration by administrators and the password reset process available to users on the login page. ## Overview The password reset system works through a secure two-step verification process: 1. **Request Reset**: User provides username and email to request a password reset 2. **Verify and Reset**: User enters the reset code from email along with their new password This system requires administrators to configure email settings for sending reset codes to users. ## Administrator Setup: Email Configuration Before users can reset their passwords, administrators must configure the email settings that will be used to send password reset codes. ### Accessing Email Settings 1. Log in with an administrator account 2. Navigate to **Settings** in the main menu 3. Expand the **Email Settings** section 4. Configure the SMTP settings for password reset emails ### Required Email Configuration #### Basic SMTP Settings - **SMTP Server**: Your email provider's SMTP server (e.g., `smtp.gmail.com`) - **Port**: SMTP port number (typically `587` for StartTLS or `465` for SSL/TLS) - **From Email**: The email address that password reset emails will be sent from - **Encryption**: Choose from `None`, `SSL/TLS`, or `StartTLS` (StartTLS recommended) #### Authentication Settings - **Authentication Required**: Enable if your SMTP server requires authentication - **Username**: SMTP account username (usually the full email address) - **Password**: SMTP account password or app-specific password ### Common Email Provider Settings #### Gmail Configuration - **Server**: `smtp.gmail.com` - **Port**: `587` (StartTLS) or `465` (SSL/TLS) - **Encryption**: StartTLS or SSL/TLS - **Authentication**: Required - **Username**: Your full Gmail address - **Password**: App-specific password (not your regular Gmail password) **Note**: Gmail requires generating an App Password for SMTP access. Regular Gmail passwords will not work. #### Outlook/Hotmail Configuration - **Server**: `smtp-mail.outlook.com` - **Port**: `587` - **Encryption**: StartTLS - **Authentication**: Required - **Username**: Your full Outlook email address - **Password**: Your Outlook account password ### Testing Email Configuration Before saving email settings, administrators should test the configuration: 1. Fill in all required SMTP settings 2. Click **Test Email Settings** 3. The system will send a test email to your account email address 4. Check your inbox for the test email 5. If successful, click **Save Settings** to apply the configuration 6. If the test fails, review and correct the settings before trying again ### Security Considerations - **App Passwords**: Many email providers require app-specific passwords for SMTP access - **Secure Storage**: Email passwords are securely stored and encrypted in the database - **From Address**: Use a dedicated email address for system notifications - **Rate Limiting**: Consider email provider sending limits for high-volume installations ## User Password Reset Process Once email settings are configured, users can reset their passwords through the login page. ### Initiating a Password Reset #### Step 1: Access Reset Option 1. Navigate to the Pinepods login page 2. Click the **"Forgot Password?"** link below the password field 3. A password reset modal will appear #### Step 2: Provide Account Information 1. Enter your **username** in the username field 2. Enter the **email address** associated with your account 3. Click **Submit** to request the reset code 4. The system will send a password reset code to your email address ### Completing the Password Reset #### Step 3: Check Your Email 1. Check your email inbox for a message from Pinepods 2. Look for an email containing your password reset code 3. Copy or note the reset code from the email 4. Return to the Pinepods interface #### Step 4: Enter New Password and Code 1. In the password reset interface, you'll see fields for: - **Reset Code**: Enter the code from your email - **New Password**: Enter your desired new password 2. Fill in both fields accurately 3. Click **Submit** to complete the password reset #### Step 5: Login with New Password 1. After successful reset, you'll be returned to the login page 2. Log in using your username and new password 3. Your account is now accessible with the new password --- ## RSS Feed Integration Pinepods provides comprehensive RSS feed integration that allows you to access your podcast subscriptions from any RSS-compatible podcast application. This feature enables cross-platform synchronization and gives you the flexibility to use your preferred podcast client while maintaining centralized subscription management. ## Overview The RSS feed system in Pinepods generates a personalized RSS feed URL that contains all your podcast subscriptions aggregated into a single feed. This URL can be used in any podcast application that supports RSS feeds, enabling you to access your Pinepods library from multiple devices and applications. ### Key Features - **Universal Access**: Subscribe to your entire Pinepods library from any RSS-compatible app - **Single Podcast Feeds**: Generate RSS feeds for individual podcasts - **Secure Access**: RSS URLs include special RSS Keys - These are different from user API keys and can be safely shared to other people - **Real-time Synchronization**: Changes to your subscriptions are reflected in the RSS feed - **Cross-platform Compatibility**: Works with all major podcast applications ## Accessing RSS Feed Settings 1. Navigate to **Settings** in the main menu 2. Expand the **RSS Feed Settings** section 3. Configure your RSS feed preferences ## Enabling RSS Feeds ### Step-by-Step Activation 1. **Navigate to Settings**: Open the RSS Feed Settings section 2. **Toggle Enable**: Click the **"Enable RSS Feeds"** toggle switch 3. **Wait for Generation**: The system will generate your personalized RSS feed URL 4. **Copy URL**: Once enabled, your RSS feed URL will be displayed ### RSS Feed URL Generation When RSS feeds are enabled, Pinepods automatically: - Generates a unique RSS key for your account - Creates a personalized RSS feed URL - Provides a copy button for easy URL sharing The generated URL follows this format: ``` https://your-server.com/rss/[USER_ID]?api_key=[RSS_KEY] ``` ## Using Your RSS Feed ### Adding to Podcast Applications #### Universal Steps 1. **Copy Your URL**: Use the copy button in RSS Feed Settings to copy your personal RSS URL 2. **Open Podcast App**: Launch your preferred podcast application 3. **Add RSS Feed**: Look for "Add RSS Feed", "Subscribe by URL", or similar option 4. **Paste URL**: Enter your Pinepods RSS feed URL 5. **Subscribe**: Complete the subscription process in your podcast app ### Individual Podcast RSS Feeds In addition to the aggregated feed, Pinepods also provides RSS feeds for individual podcasts: 1. **Navigate to Podcast**: Open any podcast in your library 2. **Find RSS Icon**: Look for the RSS icon on the podcast page 3. **Get Individual URL**: Click the RSS icon to get a direct RSS feed for that specific podcast 4. **Subscribe Separately**: Use this URL to subscribe to just that podcast in other apps An interesting use case for this functionality could be to subscribe to a premium feed in an app that normally wouldn't support them. ## RSS Feed Content ### What's Included Your RSS feed contains: - **All Subscribed Podcasts**: Every podcast in your Pinepods library - **Episode Information**: Title, description, publication date, duration - **Audio URLs**: Direct links to episode audio files - **Artwork**: Podcast and episode artwork when available - **Metadata**: Categories, tags, and other podcast metadata ### Real-time Updates The RSS content is generated as-requested immediately. Therefore: The RSS feed automatically reflects: - **New Subscriptions**: Podcasts added to your Pinepods library - **Removed Subscriptions**: Podcasts unsubscribed from your library - **New Episodes**: Latest episodes from your subscribed podcasts - **Episode Updates**: Changes to episode information or availability --- ## Setting Up Notifications Pinepods provides comprehensive push notification support to keep you informed about new podcast episodes, system updates, and other important events. The notification system supports multiple platforms and authentication methods to fit your preferred notification workflow. ## Overview Pinepods supports push notifications through two popular notification platforms: - **ntfy**: A simple, lightweight notification service (default) - **Gotify**: A self-hosted notification server for privacy-focused users Both platforms allow you to receive real-time notifications on your mobile devices, desktop computers, and other connected devices. ## Supported Notification Platforms ### ntfy (Recommended) - **Public Service**: Uses the free ntfy.sh service by default - **Self-Hosted Option**: Supports custom ntfy server installations - **Multi-Device**: Send notifications to multiple devices using the same topic - **Authentication**: Supports both username/password and access token authentication (Optional) - **Cross-Platform**: Available on iOS, Android, and desktop ### Gotify - **Self-Hosted**: Requires your own Gotify server installation - **Privacy Focused**: Complete control over your notification data - **Token-Based**: Uses application tokens for secure authentication - **Web Interface**: Manage notifications through Gotify's web interface ## Accessing Notification Settings 1. Navigate to **Settings** in the main menu 2. Expand the **Notification Settings** section 3. Configure your preferred notification platform and credentials ## Setting Up ntfy Notifications ### Basic ntfy Setup #### Step 1: Choose Platform 1. In Notification Settings, ensure **ntfy** is selected as the platform 2. Check the **Enable Notifications** checkbox to activate notifications #### Step 2: Configure ntfy Topic 1. **Topic Name**: Enter a unique topic name for your notifications - Use something personal and unique (e.g., `pinepods-johnsmith-2024`) - Avoid common words to prevent receiving other users' notifications - Topic names are case-sensitive and can include letters, numbers, and hyphens #### Step 3: Set Server URL 1. **Default Server**: Leave as `https://ntfy.sh` to use the free public service 2. **Custom Server**: Enter your self-hosted ntfy server URL if you have one 3. Ensure the URL includes the protocol (`https://` or `http://`) ### ntfy Authentication (Optional) ntfy supports two authentication methods - choose one: #### Option 1: Username and Password 1. Enter your **ntfy username** in the Username field 2. Enter your **ntfy password** in the Password field 3. Leave the Access Token field empty #### Option 2: Access Token 1. Leave Username and Password fields empty 2. Enter your **ntfy access token** in the Access Token field 3. Access tokens can be generated in your ntfy account settings **Note**: You can only use one authentication method at a time. The interface will automatically disable the other method when you start entering credentials. ## Setting Up Gotify Notifications ### Prerequisites - A running Gotify server installation - Administrative access to create application tokens ### Gotify Setup Process #### Step 1: Choose Platform 1. In Notification Settings, select **Gotify** as the platform 2. Check the **Enable Notifications** checkbox #### Step 2: Configure Server 1. **Gotify Server URL**: Enter your Gotify server's complete URL - Include the protocol: `https://your-gotify-server.com` - Include the port if non-standard: `https://gotify.example.com:8080` #### Step 3: Application Token 1. **Create Token**: Log into your Gotify server's web interface 2. **Navigate to Apps**: Go to the Applications section 3. **Create Application**: Create a new application for Pinepods 4. **Copy Token**: Copy the generated application token 5. **Enter Token**: Paste the token into the Gotify App Token field in Pinepods ## Testing Your Notification Setup ### Test Notification Feature Once you've configured your notification settings: 1. **Save Settings**: Click **Save Settings** to apply your configuration 2. **Test Button**: A **Send Test Notification** button will appear 3. **Send Test**: Click the button to send a test notification 4. **Verify Receipt**: Check your device to confirm the test notification was received ## Notification Types ### Episode Notifications Pinepods can send notifications for: - **New Episodes**: When new episodes are available for your subscribed podcasts (More notification options coming in the future) --- ## PinePods Podcast Synchronization Guide ## Introduction PinePods 0.7.8 introduced a completely rebuilt podcast synchronization system, offering multiple ways to keep your podcast subscriptions and listening progress in sync across different devices and applications. This guide explains the available synchronization options, with a particular focus on the built-in GPodder API server. ## Synchronization Options Overview PinePods now offers three primary synchronization methods: 1. **Internal GPodder API** (Recommended) - A full-featured built-in GPodder-compatible sync server 2. **External GPodder Server** - Connect to an existing third-party GPodder server 3. **Nextcloud Sync** - Connect to a Nextcloud instance with the GPodder plugin These options can be configured in the **Podcast Sync Settings** section of your PinePods installation. ## Internal GPodder API (Recommended) ### What is the Internal GPodder API? The Internal GPodder API is a feature introduced in PinePods 0.7.8 that embeds a full-featured GPodder-compatible synchronization server directly into PinePods itself. This means PinePods can now act as its own podcast synchronization server without requiring any additional external services. ### Key Benefits - **Single Server Maintenance** - No need to set up and maintain a separate GPodder server - **High Performance** - Built in Golang for exceptional speed and reliability - **Simplified Authentication** - Uses your existing PinePods credentials - **Advanced Device Management** - Full support for managing multiple devices - **Manual Synchronization Options** - Control exactly when and how your podcasts sync - **Scalability** - Designed to handle thousands of podcasts efficiently - **Direct Database Integration** - Uses the same database as your PinePods installation ### Setting Up Internal GPodder Sync 1. Navigate to **Settings → Podcast Sync Settings** 2. In the "Internal Gpodder API" section, toggle the switch to "Enabled" 3. Your internal GPodder server is now active and ready to use. Seriously, it's that easy. ### Connecting External Apps to Internal GPodder When connecting apps like AntennaPod (Android) to your PinePods server: - **Server URL**: Use your PinePods server address (e.g., `https://my-pinepods-server.com`) - **Username**: Your PinePods username - **Password**: Your PinePods password ## Device Management With the new GPodder sync system, you can manage multiple devices through an intuitive interface: - **Add New Devices** - Register smartphones, tablets, desktops, or other instances (Generally apps register their own device as they connect the first time.) - **Set Default Device** - Designate a primary device for automatic synchronization - **Manual Sync Controls** - Push or pull podcast subscriptions as needed manually. This also occurs automatically in the background. **Note** that which ever devices is selected in the dropdown is the one you will sync from. For example, if you have device-1 selected in the dropdown and device-2 if your default device in Pinepods, you'll sync podcasts associated with device-1 to device-2. ### Advanced Device Features - **Device Types** - Categorize your devices (mobile, desktop, laptop, server, etc.) - **Device Captions** - Add descriptive names to help identify your devices - **Last Sync Tracking** - Monitor when each device last connected - **Default Device Indicators** - Easily identify your primary device ## External GPodder Server If you already have an existing GPodder server that you wish to continue using, PinePods supports connecting to it as a client. ### Configuration Steps 1. Navigate to **Settings → Podcast Sync Settings** 2. Ensure the "Internal Gpodder API" is disabled 3. In the "GPodder-compatible Server" section, enter: - Server URL - Username - Password 4. Click "Test Connection" to verify your settings 5. Click "Authenticate" to establish the connection ### Notes on External GPodder Sync While fully supported, external GPodder synchronization requires maintaining a separate server and potentially dealing with additional configuration complexity. For most users, the internal GPodder API will provide a simpler and more integrated experience. ## Nextcloud Sync PinePods supports synchronization with Nextcloud instances that have the GPodder plugin installed. ### Configuration Steps 1. Navigate to **Settings → Podcast Sync Settings** 2. Ensure the "Internal Gpodder API" is disabled 3. In the "Nextcloud Sync" section, enter your Nextcloud server URL 4. Click "Authenticate" and follow the authentication flow in the new browser tab ### Limitations of Nextcloud Sync Nextcloud sync provides basic podcast subscription synchronization but lacks some advanced features: - Limited device management capabilities - Fewer configuration options - Potentially slower synchronization - May take up to 20 minutes to fully synchronize all podcasts This option is primarily useful for users who are already heavily integrated with Nextcloud and prefer to keep everything within that ecosystem. ## Choosing the Right Sync Option ### Why Choose Internal GPodder API (Recommended) - **Simplicity**: One server to maintain instead of two - **Performance**: Golang-based implementation offers superior speed - **Integration**: Direct access to PinePods database for efficiency - **Features**: Full device management and manual sync controls - **Authentication**: Uses existing PinePods credentials - **Reliability**: Some of the other podcast sync servers aren't particularly reliable ### When to Consider External GPodder - You already have a well-established GPodder server - Your current setup includes multiple applications relying on your existing server - You have specific customizations to your GPodder server that PinePods doesn't replicate ### When to Consider Nextcloud Sync - You're deeply invested in the Nextcloud ecosystem - You primarily use Nextcloud's podcast features already - You prefer centralized management through Nextcloud ### If you notice issues - Check the PinePods logs for any error messages - Ensure your PinePods installation is updated to the latest version - Verify that any external GPodder server or Nextcloud instance is accessible - Open an issue on the Pinepods Repo. Please include which option you're using, and if using an external option please provide which one. Not all gpodder sync servers are the same. ## FAQ **Q: Will my existing podcast subscriptions be deleted when enabling podcast sync?** A: Almost certainly no. There could be a situation where if you have a well established Gpodder Sync server elsewhere it could remove some. I would recommend backing up your podcasts via opml before enabling a Gpodder server. **Q: Will my existing podcast subscriptions transfer automatically?** A: Yes, when you enable synchronization, your current PinePods subscriptions will be available to sync to other devices. This includes episode listen times. **Q: How often does synchronization occur?** A: Every 15 mins. **Q: My podcasts don't seem to be syncing over. What should I do?** A: Sometimes it can take awhile when it's onboarding a lot of podcasts. There can be a lot of data to parse. **Q: Can I use multiple sync methods simultaneously?** A: No, you should choose one synchronization method. Enabling the internal GPodder API will disable external sync options. **Q: What information is synchronized?** A: Typically, podcast subscriptions and episode play states are synchronized. Exact details may vary by client application as some support more features than others. **Q: Is my listening data secure?** A: Yes, as long as your Pinepods server is behind an https connection transmission of the data to any app is secure. Especially with the internal GPodder API which uses your existing PinePods authentication system and doesn't require exposing credentials to third-party services. --- ## PodPeopleDB Integration Pinepods integrates with the PodPeopleDB in order to expand host tracking between podcasts. This is a community project that listeners of the given podcasts submit host information to. It's intended as a suppliment for Podcasts that don't currently support the Person Podcasting 2.0 tag. Entering host information for a given podcast will allow others to see these hosts as well. Because of this, maintaining integrety for hosts is vital. There's a simple approval process for submitted hosts to ensure submitteed hosts are actually corrrect and to prevent abuse. ### Automatic Import via podcast:person Tags PodPeopleDB automatically imports host and guest information from podcast feeds that use the podcast:person namespace. If your podcast uses these tags, your host information will be automatically imported when someone looks up your podcast. You won't be allowed to submit hosts for podcasts that support this. Jane Smith ### Manual Submission If you open up a podcast without hosts associated with it yet you'll see a link to submit hosts to the PodPeople page for that specific podcast. ![People Empty Podcast;](/img/peopleempty.png) Clicking that link will present you with a page to for the podcast where you can enter host information. Fill in the host details: Name (required) Role (Host or Guest) Description Link to more information Profile image URL Submit for approval Please enter all the information if you can. The image url is optional, but should be entered if possible. Approval Process To maintain data quality, all manual submissions are reviewed before being added to the database. This typically takes an hour or two at most. If you'd prefer to add your own hosts without approval you can always self-host PodPeopleDB if you'd prefer. --- ## Welcome Welcome to the Pinepods official documentation site! Feel free to browse around and check out the docs. Make sure you join the Pinepods [discord](https://discord.gg/ZkrDqPrf)! --- ## A Note About iOS Development and Open Source ## With a beta Android client out where is the ios version? I wanted to take a moment to address questions about an iOS version of the Pinepods client. I have gotten them plenty of times before. The short answer is: yes, it's coming, but there are some hurdles we need to navigate first. As an open-source developer, I've poured countless hours into making Pinepods the best it can be. The Android app is now live (in beta with some known issues), but when it comes to iOS, Apple presents a challenge for open-source projects. Unlike Android, which allows developers to freely distribute apps they've built, Apple requires a $99/year developer account just to compile and distribute iOS apps. This creates an interesting dilemma. While I'm happy to donate my time and expertise to build and maintain Pinepods, the Apple developer fee represents a recurring financial commitment. As primarily an Android user myself, it makes sense to focus first on perfecting the Android experience before taking on this additional cost. My current goal is to establish a sustainable way to cover the Apple developer fee through community support. This isn't about profit – it's simply about ensuring I can maintain consistent iOS availability without it becoming a personal financial burden. I believe that once we have about $100 in annual donations, we can confidently move forward with iOS development knowing I can sustain it long-term. This doesn't mean an iOS version isn't happening – quite the opposite. The groundwork is already laid in the codebase because the client is built with Tauri. If I paid the $99 I could go compile to ios tomorrow. But I want to be transparent about here. In the meantime, I'm focusing on making the Android app as polished as possible, which will ultimately benefit the iOS version directly because it's the same codebase. If you're interested in helping make the iOS version a reality sooner, consider supporting the project either via [buy me a coffee](https://buymeacoffee.com/collinscoffee) or [Github sponsors](https://github.com/sponsors/madeofpendletonwool). I will eventually pay this regardless. I just don't want to until the app is the best it can be. And regardless of platform, thank you for being part of the Pinepods community. Stay tuned for updates, and happy podcasting! --- ## PodPeopleDB: Building the IMDB of Podcasting In the ever-expanding universe of podcasting, there's been a crucial piece missing from the puzzle: Standardization. While this can cause some challenges, it does allow the podcasting space to be accessible, and open to all. This does however mean that some features tend to be difficult to implement when building a podcast client, and some podcasts implement certain tags and features into their feeds while others leave them out entirely; especially as the Podcasting 2.0 standard has begun rolling out. A lack of governing body has meant that in the podcasting space adoption is a slow curve as some podcasts get onboard with the new features and others don't even have them on their radar. That's where PodPeopleDB comes in - an open-source project designed to bridge this gap and enhance the podcast discovery experience with the help of the community. ## The Problem with Podcast Discovery The podcasting ecosystem has evolved tremendously over the years, with excellent tools for finding shows by topic, name, or category. [Around 2003](https://www.descript.com/blog/article/history-of-podcasts) Dave Winer embeded an audio file in an RSS feed, and Apple became quick to adopt it and build audio based feeds into the budding world of the iPod. Frankly, Apple did a good job with this when building out the standard because they left it relatively open. It does mean however that to this day there's leftover remnants of itunes all over in a standard Podcast feed. See the example below: ``` Up First from NPR https://www.npr.org/podcasts/510318/up-first Some Stuff goes here Copyright 2015-2021 NPR - For Personal Use Only NPR Feed Publish Service v1.17.11 en-us NPR no podcasts@npr.org NPR episodic https://media.npr.org/assets/img/2022/09/23/up-first_tile_npr-network-01_sq-cd1dc7e35846274fc57247cfcb9cd4dddbb2d635.jpg?s=1400&c=66&f=jpg Up First from NPR https://www.npr.org/podcasts/510318/up-first ``` Notice all the itunes references all over in this example feed. One of the most difficult parts of creating a podcast client has been ensuring my client works for as many podcast feeds as possible since they are all so different. The Podcast Index for the past few years has been trying to change this, by ensuring a consistent but open standard for podcast feeds to adopt. This is a slow process, especially in the eyes of some of the large corporations that publish and profit off podcasts. One of the greatest features of the Podcasting 2.0 standard is the Person tag. Which allows creators to add hosts and guest information to podcasts and individual episodes. This makes following specific hosts or guests across different shows possible, and without mass adoption of this tag in the show feeds you'll end up manually searching via google for other podcasts a particular host is a part of. ## Enter PodPeopleDB PodPeopleDB is designed as a complement to the Podcast 2.0 movement, specifically supporting the [podcast:person tag](https://podcasting2.org/podcast-namespace/tags/person) initiative. While this tag allows podcasts to include host and guest information directly in their feeds, adoption takes time. PodPeopleDB serves as a community-driven bridge, providing this crucial metadata for podcasts that haven't yet implemented the tag. Imagine subscribting to your favorite host and following them as they make guest appearances on various other podcasts you have yet to hear about in the first place. This is possible, and with Pinepods and the help of you, is already done. ### Key Features and Benefits - **Community-Driven Data**: Listeners can submit host and guest information for their favorite shows, building a comprehensive database of podcast personalities - **Automatic Integration**: Seamlessly imports data from feeds already using the podcast:person tag. I'm not stepping on the toes of the Podcast Index. For podcasts that already use the Person tag you can't even add hosts. If every podcast used the Person tag (not happening anytime soon) this would be a dead project. - **Open API**: Free access for podcast apps and developers to enhance their discovery features. I develop, breathe and sleep open-source. If you want to access the PodPeopleDB API they are here free, and documented. If you want to host your own instance of it, download the existing database and go for it. This project and all it's data belongs to the community, I just maintain it. - **Self-Hostable**: See above, Complete control over the data with easy Docker deployment - **Fallback System**: Provides host data when it's not available in the podcast feed directly. (Guest data for episodes is in the works) - **Real-Time Updates**: Notifications via ntfy for new submissions and updates. As the creator I get these as well as anyone else I make an admin. ## Why This Matters Think about how IMDB transformed movie discovery. Before IMDB, following an actor's career or finding all movies by a specific director was a challenge. PodPeopleDB aims to bring this same level of interconnected discovery to podcasting. For podcast listeners, this means: - Finding all appearances of their favorite people across different shows - Discovering new shows through host connections - Following podcast hosts as they launch new projects For podcast creators: - Better visibility for their content through host/guest connections - Improved discoverability without requiring immediate feed modifications - Simple integration with existing podcast platforms (Open API) There's a lot of oppurtunity for federation between instances, or graphing host data between podcasts, especially since the entire database it a one click download away. ## Getting Started Whether you're a podcast app developer looking to integrate host/guest data, a podcast listener wanting to contribute information, or a platform operator interested in hosting your own instance, PodPeopleDB is designed to be accessible and easy to use. The entire platform is built off the podcastindex throughout. If you go to the [PodpeopleDB website](https://podpeopledb.com) you'll be asked to provide a podcast index id. ![Podpeople;](../../static/img/podpeopledbhome.png) Entering an id will take you to a page for that particular podcast where you can submit host information. ![Podpeople;](../../static/img/podpeoplepod.png) Note: It's much easier to just open a particular podcast in Pinepods where you'll be presented with the option to click a link directly to this page. ## Development The project is actively seeking contributors and feedback from the podcast community. Check out the [GitHub repository](https://github.com/madeofpendletonwool/podpeople-db) to get started, or visit the [documentation](https://podpeopledb.com) for integration guides and API documentation. Additional features yet to come: - Individular Guest Episode support (Currently just hosts are supported in this initial implementation) You can also check the issues on the [PodPeopleDB repo](https://github.com/madeofpendletonwool/podpeople-db/issues) ## Looking Forward While we wait for more Podcasts to implement the features built by the Podcasting 2.0 movement building this community driven bridge will ensure it's always free to implement all the greated features into every Podcasting client. Let's build this now before another company looking to profit off it builds it out instead. Podcasting can be a great experience with the option to find your favorite personalities wherever they decide to get on a mic. ## Integration with PinePods: A Perfect Partnership PodPeopleDB was designed with deep integration in mind, and nowhere is this more evident than in its seamless connection with PinePods, the open-source podcast manager. When used together, these platforms create a powerful podcast discovery and management system: - **Automatic Host Discovery**: PinePods automatically queries PodPeopleDB when displaying podcast information, enriching show details with comprehensive host data - **Enhanced Search Capabilities**: PinePods users can subscribe to hosts, following them everywhere they go. Whether or not they are subscribed to a given podcast already. - **Unified Self-Hosting**: Both platforms can be easily self-hosted together using Docker, sharing infrastructure and simplifying deployment. You can also simply use Pinepods and the hosted instance of PodPeople that I provide. This means less for you to worry about, and you can give back to the community as you contribute host information for your favorite shows. - **Shared Philosophy**: Both projects embrace open-source values and community-driven development, working together to improve the podcast listening experience If you have a podcast client of your own, whether paid or free, I invite you to implement the PodPeopleDB into it. The name of the game here is to ensure the listener gets a better experience, not locked down to the specific platform for that better experience. ## Complementing Podcast 2.0: Building Bridges, Not Walls While PodPeopleDB might seem to overlap with Podcast 2.0's person tags, I want to stress it's actually designed to complement and support this important initiative. Here's how: ### Supporting the Transition - **Fallback System**: When a podcast hasn't implemented person tags yet, PodPeopleDB provides the missing metadata - **Seamless Migration**: As podcasts adopt person tags, PodPeopleDB automatically transitions to using the official feed data - **No Lock-in**: PodPeopleDB encourages podcasters to implement person tags by making the transition smooth and beneficial ### Enhancing the Ecosystem - **Historical Data**: Maintains information for older episodes that might not have person tags - **Community Verification**: Provides a way for listeners to verify and supplement official person tag data - **Extended Metadata**: Offers additional information that might not fit within the person tag specification - Descriptions of given hosts namely. ### Best of Both Worlds PodPeopleDB takes a "yes, and" approach rather than an "either/or" stance. It recognizes that: - Some podcasts may take time to implement person tags - Older episodes might never be updated with new tags - Community input can enhance official metadata - Different use cases might require different approaches to host/guest data