Metadata-Version: 2.4
Name: offshore-podcast
Version: 0.5.1
Summary: A local-first podcast feed generator and editor.
Project-URL: Homepage, https://offshore.pressed.press
Project-URL: Repository, https://git.sr.ht/~lamons/offshore
Project-URL: Issues, https://todo.sr.ht/~lamons/offshore
Author: tianshi
License: MIT
License-File: LICENSE
Keywords: feed,generator,podcast,rss
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Multimedia :: Sound/Audio
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.111
Requires-Dist: feedparser>=6.0.11
Requires-Dist: httpx>=0.27
Requires-Dist: imagesize>=1.4.1
Requires-Dist: jinja2>=3.1
Requires-Dist: markdown-it-py>=3.0
Requires-Dist: markdownify>=0.11
Requires-Dist: mutagen>=1.47
Requires-Dist: platformdirs>=4.2
Requires-Dist: pydantic[email]>=2.6
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: rich>=13.7
Requires-Dist: typer>=0.12
Requires-Dist: uvicorn>=0.30
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# offshore

[![PyPI version](https://img.shields.io/pypi/v/offshore-podcast)](https://pypi.org/project/offshore-podcast/)

[Homepage](https://offshore.pressed.press) ･ [Repository](https://sr.ht/~lamons/offshore) ･ [PyPI package](https://pypi.org/project/offshore-podcast/) ･ [Tickets](https://todo.sr.ht/~lamons/offshore)

Local-first podcast feed generator and editor. Manage show metadata and episodes locally, generate a standards-compliant RSS 2.0 + iTunes feed, and serve or publish the output anywhere.

To contribute, please send patch to [~lamons/offshore-dev@lists.sr.ht](mailto:~lamons/offshore-dev@lists.sr.ht).

## Screenshots<sup>[†](#acknowledgement)</sup>
<table>
<tr>
<td width="33%"><a href="https://git.sr.ht/~lamons/offshore/tree/main/item/docs/0.5.0_db.jpeg"><img src="https://git.sr.ht/~lamons/offshore/blob/main/docs/0.5.0_db.jpeg" alt="Dashboard" /></a></td>
<td width="33%"><a href="https://git.sr.ht/~lamons/offshore/tree/main/item/docs/0.5.0_ss.jpeg"><img src="https://git.sr.ht/~lamons/offshore/blob/main/docs/0.5.0_ss.jpeg" alt="Episode editor" /></a></td>
<td width="34%"><a href="https://git.sr.ht/~lamons/offshore/tree/main/item/docs/0.5.0_ee.jpeg"><img src="https://git.sr.ht/~lamons/offshore/blob/main/docs/0.5.0_ee.jpeg" alt="Show settings" /></a></td>
</tr>
</table>

## Requirements

Python 3.11 or later.

## Installation

```bash
pip install offshore-podcast
```

Or from source:

```bash
pip install -e .
```

## Quick start

```bash
offshore serve          # opens the web UI at http://127.0.0.1:8765
```

## Data layout

Every show lives in its own subdirectory inside the shows root.

```
~/offshore/              # default shows root (configurable)
  <slug>/
    <slug>.json          # show and episode metadata
    <slug>.lock.json     # feed stability lock (GUID / pub_date history)
    <slug>.report.json   # check results 
    podcast.xml          # generated feed (default location)
    rss.xsl              # generated stylesheet (default location)
```

**`<slug>.json`** is the primary data file. It stores everything that ends up in the feed: show title, description, language, categories, cover image URL, feed self-link, episodes with their audio URLs, shownotes, persons, and more.

**`<slug>.lock.json`** records each episode's GUID and `pub_date` when it is first saved. Any later change to these values through a normal save is rejected, protecting subscribers from duplicate entries. Use `offshore republish` to intentionally move an episode date.

**`<slug>.report.json`** holds the result of the latest check run, including per-episode audio and image verification results. It's auto-generated to be read by offshore and should not be manually edited. 

## [Documentation](https://offshore.pressed.press/DOC/index.xml)

## Development

```bash
pip install -e ".[dev]"
python -m pytest
```

## Acknowledgement

<sup name="acknowledgement">†</sup>: The example feed in the screenshots is from [Preserve This Podcast](https://preservethispodcast.org/).  
The episode check result icons use [Bootstrap Icons](https://icons.getbootstrap.com/). 