README ¶
Private Podcast (pp)
Private Podcast is a simple application to serve podcast episodes from a S3 bucket with Google login.
Building and Running
If you have the latest go toolchain installed running go build ./cmd
should be enough.
To run the application you'll need to set the AWS environmental variables in addition to the configuration provided and documented on the CLI (see cmd/main.go for the variables and their documentation). The AWS variables that are usually needed are AWS_REGION
, AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, the region should be the region of the S3 bucket.
Database
This application requires a Postgres database, by default it connects to a local database. To run a local database for testing you can use docker run -e POSTGRES_PASSWORD=secret -e POSTGRES_USER=pp -p 5432:5432 -it postgres:12
.
S3 Bucket
NEVER change the key (name/path) of a podcast in S3, otherwise its GUID will also change, meaning that some podcast applications might show that particular episode multiple times. If you need to rename an episode you can add a metadata title (metadata with key of x-amx-meta-title
in the S3 Console) to it. Publishing date cannot be changed currently.
All podcasts in the S3 bucket should be placed in the root, have a .mp3
prefix, and start with the publishing date in YYYY-MM-DD format.
For example, a file named 2020-01-27 Hello World!.mp3
will be parsed as podcast episode that was released on the 27th of January in 2020, with a title and description of Hello World!
. All files which can't be parsed are skipped.
To add a description to a podcast, another file can be added with .txt
suffix. It's name must otherwise be exactly equal, e.g. in the example above the file would be named 2020-01-27 Hello World!.mp3.txt
.
License
pp - Private Podcast feed with Single Sign-On
Copyright (C) 2020 Maximilian Remming
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Documentation ¶
Index ¶
- Constants
- func GenerateSecret() string
- type Auth
- type AuthGoogle
- type Backend
- type BackendS3
- type Podcast
- type PodcastDetails
- type PodcastS3
- type Storage
- type StoragePostgres
- func (s StoragePostgres) CreateUser(userID string) (string, error)
- func (s StoragePostgres) Init() error
- func (s StoragePostgres) LogFeed(secret, referer, userAgent string) error
- func (s StoragePostgres) LogPodcast(secret, key, referer, userAgent string) error
- func (s StoragePostgres) ValidSecret(secret string) (bool, error)
Constants ¶
const SecretSizeBytes = 36
SecretSizeBytes is the size of the secret in bytes, it should be a multiple of 12 to make sure it's encoded nicely in base64.
Variables ¶
This section is empty.
Functions ¶
func GenerateSecret ¶
func GenerateSecret() string
GenerateSecret generates `SecretSizeBytes` bytes of secure randomness and encodes it with URL safe base64.
Types ¶
type AuthGoogle ¶
type AuthGoogle struct {
// contains filtered or unexported fields
}
func NewAuthGoogle ¶
func NewAuthGoogle(clientID, clientSecret, authURL string) AuthGoogle
func (AuthGoogle) HandleAuth ¶
func (a AuthGoogle) HandleAuth(w http.ResponseWriter, r *http.Request, storage Storage, noSecureCookie bool) error
type BackendS3 ¶
type BackendS3 struct {
// contains filtered or unexported fields
}
func NewBackendS3 ¶
func (BackendS3) ListPodcasts ¶
type Podcast ¶
type Podcast interface { Details() PodcastDetails HandlePodcast(http.ResponseWriter, *http.Request) error }
type PodcastDetails ¶
type PodcastS3 ¶
type PodcastS3 struct {
// contains filtered or unexported fields
}
func (PodcastS3) Details ¶
func (p PodcastS3) Details() PodcastDetails
func (PodcastS3) HandlePodcast ¶
type StoragePostgres ¶
type StoragePostgres struct {
// contains filtered or unexported fields
}
func NewStoragePostgres ¶
func NewStoragePostgres(connectionString string) (StoragePostgres, error)
func (StoragePostgres) CreateUser ¶
func (s StoragePostgres) CreateUser(userID string) (string, error)
func (StoragePostgres) Init ¶
func (s StoragePostgres) Init() error
func (StoragePostgres) LogFeed ¶
func (s StoragePostgres) LogFeed(secret, referer, userAgent string) error
func (StoragePostgres) LogPodcast ¶
func (s StoragePostgres) LogPodcast(secret, key, referer, userAgent string) error
func (StoragePostgres) ValidSecret ¶
func (s StoragePostgres) ValidSecret(secret string) (bool, error)