podops

package module
v0.9.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 30, 2021 License: MIT Imports: 16 Imported by: 1

README

PodOps - Programmable Podcasts

Podops is a podcast infrastructure platform that provides functionallity to automate your podcast creation workflow. It allows you to create the podcast feed and delivers media assets like mp3s or images to podcast clients.

The platform follows an API-first approach and is very light on user-facing frontends. Almost all interactions with Podops happens either using po the command line interface or by directly calling the Rest API.

If you need support or have ideas for improving Podops, please join the Podops Gitter community or visit the GitHub Issues section of this repo. Please visit the Podops document repository for installation instructions and documentation.

If you find this project interesting, please consider starring it here on GitHub!

Getting started

To use Podops, you need an API access key for https://api.podops.dev. To get your key, you have to install po, the command line tool first. After installing it, you can register your account and request a API key.

Note: While all the Podops code is here on GitHub, there is no step-by-step guide how install it on your own infrastructure at the moment. This will come later. If you want to deploy Podops on your own infrastructure TODAY, join the community on Gitter and send me a DM at @mickuehl and we will sort it out.

Download the binary

Download the latest binary for your system:

Unpack the archive and place the po binary in a directory that is on your $PATH. Verify that the command line tool is accessible:

$ po help
Register and get the API key
$ po login <your_email_address>

Podops will send you an email with a confirmation code. Use the confirmation code to exchange it for your API access key. The code is valid for 15min and can only be used once. In case you missed this time-window, start over with the login command.

$ po auth <your_email_address> <access_code>

This will retrieve your current API access code and place it in its default location $HOME/.po/config. You can verify that everything is setup correctly by issuing a command that requires authentication e.g.

$ po shows

Note: If you login for the first time, Podops will send you an email to verify your Email-Address first. Confirm by following the link in the Email. The link is valid for 15min.

Examples

Examples on how to use the Command Line Interface or Go Client SDK to create and publish your podcast are here.

Documentation

The documentation repository is here

Development

A description how to build the codebase and how to test locally is here.

Open-source but not open-contribution?

I am grateful for community involvement, bug reports, & feature requests but I do not expect code contributions at this point in time as there is not really a substantial user base or community in general. In case someone wants to contribute, I will gladly review pull requests.

There is another way to help the project: many of the most valuable contributions are in the forms of testing, feedback, and documentation. This helps to harden the software and streamlines its usage for other users.

Should you wish to contribute, please review the contribution guidelines first.

Documentation

Index

Constants

View Source
const (

	// LabelLanguage ISO-639 two-letter language code. channel.language
	LabelLanguage = "language"
	// LabelExplicit ["true"|"false"] channel.itunes.explicit
	LabelExplicit = "explicit"
	// LabelType ["Episodic"|"Serial"] channel.itunes.type
	LabelType = "type"
	// LabelBlock ["Yes"] channel.itunes.block
	LabelBlock = "block"
	// LabelComplete ["Yes"] channel.itunes.complete
	LabelComplete = "complete"
	// LabelGUID resources GUID
	LabelGUID = "guid"
	// LabelParentGUID guid of the resources parent resource
	LabelParentGUID = "parent_guid"
	// LabelDate used as e.g. publish date of an episode
	LabelDate = "date"
	// LabelSeason defaults to "1"
	LabelSeason = "season"
	// LabelEpisode positive integer 1..
	LabelEpisode = ResourceEpisode

	// ShowTypeEpisodic type of podcast is episodic
	ShowTypeEpisodic = "Episodic"
	// ShowTypeSerial type of podcast is serial
	ShowTypeSerial = "Serial"

	// EpisodeTypeFull type of episode is 'full'
	EpisodeTypeFull = "Full"
	// EpisodeTypeTrailer type of episode is 'trailer'
	EpisodeTypeTrailer = "Trailer"
	// EpisodeTypeBonus type of episode is 'bonus'
	EpisodeTypeBonus = "Bonus"

	// ResourceTypeExternal references an external URL
	ResourceTypeExternal = "external"
	// ResourceTypeLocal references a local resource
	ResourceTypeLocal = "local"
	// ResourceTypeImport references an external resources that will be imported into the CDN
	ResourceTypeImport = "import"

	// ResourceShow is referencing a resource of type "show"
	ResourceShow = "show"
	// ResourceEpisode is referencing a resource of type "episode"
	ResourceEpisode = "episode"
	// ResourceAsset is referencing any media or binary resource e.g. .mp3 or .png
	ResourceAsset = "asset"
	// ResourceALL is a wildcard for any kind of resource
	ResourceALL = "all"
)
View Source
const (
	// Version specifies the verion of the API and its structs
	Version = "v1"

	// MajorVersion of the API
	MajorVersion = 0
	// MinorVersion of the API
	MinorVersion = 9
	// FixVersion of the API
	FixVersion = 10
)
View Source
const (
	// NamespacePrefix namespace for the client and CLI
	NamespacePrefix = "/a/v1"
)

Variables

View Source
var (
	// DefaultEndpoint points to the portal
	DefaultEndpoint string = env.GetString("BASE_URL", defaultEndpoint)

	// DefaultAPIEndpoint points to the API
	DefaultAPIEndpoint string = env.GetString("API_ENDPOINT", defaultAPIEndpoint)

	// DefaultCDNEndpoint points to the CDN
	DefaultCDNEndpoint string = env.GetString("CDN_URL", defaultCDNEndpoint)

	// BucketProduction is the canonical name of the production bucket
	BucketProduction string = env.GetString("BUCKET_PRODUCTION", defaultBucketProduction)

	// BucketCDN is the canonical name of the CDN bucket
	BucketCDN string = env.GetString("BUCKET_CDN", defaultBucketCDN)

	// StorageEndpoint is the direct link to assets in Google Storage
	StorageEndpoint string = env.GetString("STORAGE_ENDPOINT", defaultStorageEndpoint)
)
View Source
var (
	// VersionString is the canonical API description
	VersionString string = fmt.Sprintf("%d.%d.%d", MajorVersion, MinorVersion, FixVersion)
	// UserAgentString identifies any http request podops makes
	UserAgentString string = fmt.Sprintf("PodOps %d.%d.%d", MajorVersion, MinorVersion, FixVersion)
)
View Source
var (
	PodopsClientConfigurationErr error = fmt.Errorf("client: invalid configuration")
)

Functions

func ValidResourceName added in v0.9.10

func ValidResourceName(name string) bool

ValidResourceName verifies that a name is valid for a resource. The following rules apply:

'name' must contain only lowercase letters, numbers, dashes (-), underscores (_). 'name' must contain 8-44 characters. Spaces and dots (.) are not allowed.

Types

type Asset added in v0.9.10

type Asset struct {
	URI    string `json:"uri" yaml:"uri" binding:"required"`        // REQUIRED
	Title  string `json:"title,omitempty" yaml:"title,omitempty"`   // OPTIONAL
	Anchor string `json:"anchor,omitempty" yaml:"anchor,omitempty"` // OPTIONAL
	Rel    string `json:"rel,omitempty" yaml:"rel,omitempty"`       // OPTIONAL
	Type   string `json:"type,omitempty" yaml:"type,omitempty"`     // OPTIONAL
	Size   int    `json:"size,omitempty" yaml:"size,omitempty"`     // OPTIONAL
}

Asset provides a link to a media resource

func (*Asset) AssetName added in v0.9.10

func (r *Asset) AssetName() string

func (*Asset) FingerprintURI added in v0.9.10

func (r *Asset) FingerprintURI(parent string) string

FingerprintURI is used in rewriting the URI when Rel == IMPORT

func (*Asset) ResolveURI added in v0.9.10

func (r *Asset) ResolveURI(cdn, parent string) string

ResolveURI re-writes the URI

func (*Asset) Validate added in v0.9.10

func (r *Asset) Validate(v *validator.Validator) *validator.Validator

Validate verifies the integrity of struct Resource

URI    string `json:"uri" yaml:"uri" binding:"required"`        // REQUIRED
Title  string `json:"title,omitempty" yaml:"title,omitempty"`   // OPTIONAL
Anchor string `json:"anchor,omitempty" yaml:"anchor,omitempty"` // OPTIONAL
Rel    string `json:"rel,omitempty" yaml:"rel,omitempty"`       // OPTIONAL
Type   string `json:"type,omitempty" yaml:"type,omitempty"`     // OPTIONAL
Size   int    `json:"size,omitempty" yaml:"size,omitempty"`     // OPTIONAL

type BuildRequest added in v0.9.10

type BuildRequest struct {
	GUID         string `json:"guid" binding:"required"`
	FeedURL      string `json:"feed"`
	FeedAliasURL string `json:"alias"`
}

BuildRequest initiates the build of the feed

type Category added in v0.9.10

type Category struct {
	Name        string   `json:"name" yaml:"name" binding:"required"`      // REQUIRED
	SubCategory []string `json:"subcategory" yaml:"subcategory,omitempty"` // OPTIONAL
}

Category is the show/episodes category and it's subcategories

func (*Category) Validate added in v0.9.10

func (c *Category) Validate(v *validator.Validator) *validator.Validator

Validate verifies the integrity of struct Category

Name        string   `json:"name" yaml:"name" binding:"required"`      // REQUIRED
SubCategory []string `json:"subcategory" yaml:"subcategory,omitempty"` // OPTIONAL

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a client for interacting with the PodOps service.

Clients should be reused instead of created as needed. The methods of Client are safe for concurrent use by multiple goroutines.

func New added in v0.9.10

func New(ctx context.Context, o *ClientOption) (*Client, error)

func NewClient

func NewClient(ctx context.Context, token string, opts ...*ClientOption) (*Client, error)

NewClient creates a new podcast client.

Clients should be reused instead of created as needed. The methods of a client instance are threadsafe.

func (*Client) APIEndpoint added in v0.9.10

func (cl *Client) APIEndpoint() string

func (*Client) Build

func (cl *Client) Build(production string) (*BuildRequest, error)

Build invokes the BuildEndpoint

func (*Client) CDNEndpoint added in v0.9.10

func (cl *Client) CDNEndpoint() string

func (*Client) CreateProduction

func (cl *Client) CreateProduction(name, title, summary string) (*Production, error)

CreateProduction invokes the CreateProductionEndpoint

func (*Client) CreateResource

func (cl *Client) CreateResource(production, kind, guid string, force bool, rsrc interface{}) (int, error)

CreateResource invokes the ResourceEndpoint

func (*Client) DefaultEndpoint added in v0.9.10

func (cl *Client) DefaultEndpoint() string

func (*Client) DefaultProduction added in v0.9.10

func (cl *Client) DefaultProduction() string

func (*Client) DeleteResource added in v0.9.10

func (cl *Client) DeleteResource(production, kind, guid string) (int, error)

DeleteResource deletes a resources

func (*Client) FindResource added in v0.9.10

func (cl *Client) FindResource(guid string, rsrc interface{}) error

FindResource returns a resource file

func (*Client) GetResource added in v0.9.10

func (cl *Client) GetResource(production, kind, guid string, rsrc interface{}) error

GetResource returns a resource file

func (*Client) IsValid added in v0.9.10

func (cl *Client) IsValid() bool

IsValid checks if all configuration parameters are provided

func (*Client) Productions

func (cl *Client) Productions() (*ProductionList, error)

Productions retrieves a list of productions

func (*Client) Realm added in v0.9.10

func (cl *Client) Realm() string

func (*Client) Resources

func (cl *Client) Resources(production, kind string) (*ResourceList, error)

Resources retrieves a list of resources

func (*Client) SetProduction

func (cl *Client) SetProduction(production string)

func (*Client) Token

func (cl *Client) Token() string

func (*Client) UpdateResource

func (cl *Client) UpdateResource(production, kind, guid string, force bool, rsrc interface{}) (int, error)

UpdateResource invokes the ResourceEndpoint

func (*Client) Upload

func (cl *Client) Upload(production, path string, force bool) error

Upload invokes the UploadEndpoint

type ClientOption added in v0.9.10

type ClientOption struct {
	Token           string
	Production      string
	APIEndpoint     string
	CDNEndpoint     string
	DefaultEndpoint string
}

Client is a client for interacting with the PodOps service.

Clients should be reused instead of created as needed. The methods of Client are safe for concurrent use by multiple goroutines.

func DefaultClientOptions added in v0.9.10

func DefaultClientOptions() *ClientOption

DefaultClientOptions returns a default configuration bases on ENV variables

func (ClientOption) IsValid added in v0.9.10

func (co ClientOption) IsValid() bool

IsValid checks if all configuration parameters are provided

func (ClientOption) Merge added in v0.9.10

func (co ClientOption) Merge(opts *ClientOption) *ClientOption

Merge clones co and combines it with the provided options

type Episode added in v0.9.10

type Episode struct {
	APIVersion  string             `json:"apiVersion" yaml:"apiVersion" binding:"required"`   // REQUIRED default: v1.0
	Kind        string             `json:"kind" yaml:"kind" binding:"required"`               // REQUIRED default: episode
	Metadata    Metadata           `json:"metadata" yaml:"metadata" binding:"required"`       // REQUIRED
	Description EpisodeDescription `json:"description" yaml:"description" binding:"required"` // REQUIRED
	Image       Asset              `json:"image" yaml:"image" binding:"required"`             // REQUIRED 'item.itunes.image'
	Enclosure   Asset              `json:"enclosure" yaml:"enclosure" binding:"required"`     // REQUIRED
}

Episode holds all metadata related to a podcast episode

func (*Episode) GUID added in v0.9.10

func (e *Episode) GUID() string

GUID is a convenience method to access the resources guid

func (*Episode) Parent added in v0.9.10

func (e *Episode) Parent() string

ParentGUID is a convenience method to access the resources parent guid

func (*Episode) PublishDate added in v0.9.10

func (e *Episode) PublishDate() string

PublishDate is a convenience method to access the pub date

func (*Episode) PublishDateTimestamp added in v0.9.10

func (e *Episode) PublishDateTimestamp() int64

PublishDateTimestamp converts a RFC1123Z formatted timestamp into UNIX timestamp

func (*Episode) Validate added in v0.9.10

func (e *Episode) Validate(v *validator.Validator) *validator.Validator

Validate verifies the integrity of struct Episode

APIVersion  string             `json:"apiVersion" yaml:"apiVersion" binding:"required"`   // REQUIRED default: v1.0
Kind        string             `json:"kind" yaml:"kind" binding:"required"`               // REQUIRED default: episode
Metadata    Metadata           `json:"metadata" yaml:"metadata" binding:"required"`       // REQUIRED
Description EpisodeDescription `json:"description" yaml:"description" binding:"required"` // REQUIRED
Image       Resource           `json:"image" yaml:"image" binding:"required"`             // REQUIRED 'item.itunes.image'
Enclosure   Resource           `json:"enclosure" yaml:"enclosure" binding:"required"`     // REQUIRED

type EpisodeDescription added in v0.9.10

type EpisodeDescription struct {
	Title       string `json:"title" yaml:"title" binding:"required"`                                 // REQUIRED 'item.title' 'item.itunes.title'
	Summary     string `json:"summary" yaml:"summary" binding:"required"`                             // REQUIRED 'item.description'
	EpisodeText string `json:"episodeText,omitempty" yaml:"episodeText,omitempty" binding:"required"` // REQUIRED 'item.itunes.summary'
	Link        Asset  `json:"link" yaml:"link"`                                                      // RECOMMENDED 'item.link'
	Duration    int    `json:"duration" yaml:"duration" binding:"required"`                           // REQUIRED 'item.itunes.duration'
}

EpisodeDescription holds essential episode metadata

func (*EpisodeDescription) Validate added in v0.9.10

Validate verifies the integrity of struct EpisodeDescription

Title       string   `json:"title" yaml:"title" binding:"required"`                                 // REQUIRED 'item.title' 'item.itunes.title'
Summary     string   `json:"summary" yaml:"summary" binding:"required"`                             // REQUIRED 'item.description'
EpisodeText string   `json:"episodeText,omitempty" yaml:"episodeText,omitempty" binding:"required"` // REQUIRED 'item.itunes.summary'
Link        Resource `json:"link" yaml:"link"`                                                      // RECOMMENDED 'item.link'
Duration    int      `json:"duration" yaml:"duration" binding:"required"`                           // REQUIRED 'item.itunes.duration'

type ImportRequest added in v0.9.10

type ImportRequest struct {
	Source   string `json:"src" binding:"required"`
	Dest     string `json:"dest" binding:"required"`
	Original string `json:"original" binding:"required"`
}

ImportRequest is used by the import task

type Metadata added in v0.9.10

type Metadata struct {
	Name   string            `json:"name" yaml:"name" binding:"required"` // REQUIRED <unique name>
	Labels map[string]string `json:"labels" yaml:"labels,omitempty"`      // REQUIRED
}

Metadata contains information describing a resource

func (*Metadata) Validate added in v0.9.10

func (m *Metadata) Validate(v *validator.Validator) *validator.Validator

Validate verifies the integrity of struct Metadata

Name   string            `json:"name" yaml:"name" binding:"required"` // REQUIRED <unique name>
Labels map[string]string `json:"labels" yaml:"labels,omitempty"`      // REQUIRED

type Owner added in v0.9.10

type Owner struct {
	Name  string `json:"name" yaml:"name" binding:"required"`   // REQUIRED
	Email string `json:"email" yaml:"email" binding:"required"` // REQUIRED
}

Owner describes the owner of the show/podcast

func (*Owner) Validate added in v0.9.10

func (o *Owner) Validate(v *validator.Validator) *validator.Validator

Validate verifies the integrity of struct Owner

Name  string `json:"name" yaml:"name" binding:"required"`   // REQUIRED
Email string `json:"email" yaml:"email" binding:"required"` // REQUIRED

type Production added in v0.9.10

type Production struct {
	Name      string `json:"name" binding:"required"`
	GUID      string `json:"guid,omitempty"`
	Owner     string `json:"owner"`
	Title     string `json:"title"`
	Summary   string `json:"summary"`
	BuildDate int64  `json:"build_date"`
	// internal
	Created int64 `json:"-"`
	Updated int64 `json:"-"`
}

Production is the parent struct of all other resources.

type ProductionList added in v0.9.10

type ProductionList struct {
	Productions []*Production `json:"productions" `
}

ProductionList returns a list of productions

type Resource added in v0.9.10

type Resource struct {
	Name       string `json:"name"`
	GUID       string `json:"guid"`
	Kind       string `json:"kind"`
	ParentGUID string `json:"parent_guid"`
	Location   string `json:"location"` // path to the .yaml
	// Metadata used in e.g. the web UI
	Title     string `json:"title"`
	Summary   string `json:"summary"`
	Published int64  `json:"published"`
	Index     int    `json:"index"`  // A running number that can be used to sort resources, e.g. episode number
	Extra1    string `json:"extra1"` // These two attributes are just placeholders for any kind of resource type specific data.
	Extra2    string `json:"extra2"` // One possible use is to e.g. store the URL of an episodes media file here.
	// Media metadata used for e.g. .mp3/.png
	Image       string `json:"image"` // Full URL to the show/episode image
	ContentType string `json:"content_type"`
	Duration    int64  `json:"duration"`
	Size        int64  `json:"size"`
	// internal
	Created int64 `json:"-"`
	Updated int64 `json:"-"`
}

Resource is used to maintain a repository of all existing resources across all shows

func (*Resource) GetPublicLocation added in v0.9.10

func (r *Resource) GetPublicLocation() string

GetPublicLocation returns the public url of a resource if it exists on the CDN or an empty string otherwise

type ResourceList added in v0.9.10

type ResourceList struct {
	Resources []*Resource `json:"resources" `
}

ResourceList returns a list of resources

type ResourceMetadata added in v0.9.10

type ResourceMetadata struct {
	APIVersion string   `json:"apiVersion" yaml:"apiVersion" binding:"required"` // REQUIRED default: v1.0
	Kind       string   `json:"kind" yaml:"kind" binding:"required"`             // REQUIRED default: show
	Metadata   Metadata `json:"metadata" yaml:"metadata" binding:"required"`     // REQUIRED
}

ResourceMetadata holds only the kind and metadata of a resource

func (*ResourceMetadata) GUID added in v0.9.10

func (r *ResourceMetadata) GUID() string

GUID is a convenience method to access the resources guid

type Show added in v0.9.10

type Show struct {
	APIVersion  string          `json:"apiVersion" yaml:"apiVersion" binding:"required"`   // REQUIRED default: v1.0
	Kind        string          `json:"kind" yaml:"kind" binding:"required"`               // REQUIRED default: show
	Metadata    Metadata        `json:"metadata" yaml:"metadata" binding:"required"`       // REQUIRED
	Description ShowDescription `json:"description" yaml:"description" binding:"required"` // REQUIRED
	Image       Asset           `json:"image" yaml:"image" binding:"required"`             // REQUIRED 'channel.itunes.image'
}

Show holds all metadata related to a podcast/show

func (*Show) GUID added in v0.9.10

func (s *Show) GUID() string

GUID is a convenience method to access the resources guid

func (*Show) Validate added in v0.9.10

func (s *Show) Validate(v *validator.Validator) *validator.Validator

Validate verifies the integrity of struct Show

APIVersion  string          `json:"apiVersion" yaml:"apiVersion" binding:"required"`   // REQUIRED default: v1.0
Kind        string          `json:"kind" yaml:"kind" binding:"required"`               // REQUIRED default: show
Metadata    Metadata        `json:"metadata" yaml:"metadata" binding:"required"`       // REQUIRED
Description ShowDescription `json:"description" yaml:"description" binding:"required"` // REQUIRED
Image       Resource        `json:"image" yaml:"image" binding:"required"`             // REQUIRED 'channel.itunes.image'

type ShowDescription added in v0.9.10

type ShowDescription struct {
	Title     string   `json:"title" yaml:"title" binding:"required"`          // REQUIRED 'channel.title' 'channel.itunes.title'
	Summary   string   `json:"summary" yaml:"summary" binding:"required"`      // REQUIRED 'channel.description'
	Link      Asset    `json:"link" yaml:"link"`                               // RECOMMENDED 'channel.link'
	Category  Category `json:"category" yaml:"category" binding:"required"`    // REQUIRED channel.category
	Owner     Owner    `json:"owner" yaml:"owner"`                             // RECOMMENDED 'channel.itunes.owner'
	Author    string   `json:"author" yaml:"author"`                           // RECOMMENDED 'channel.itunes.author'
	Copyright string   `json:"copyright,omitempty" yaml:"copyright,omitempty"` // OPTIONAL 'channel.copyright'
	NewFeed   *Asset   `json:"newFeed,omitempty" yaml:"newFeed,omitempty"`     // OPTIONAL channel.itunes.new-feed-url -> move to label
}

ShowDescription holds essential show metadata

func (*ShowDescription) Validate added in v0.9.10

Validate verifies the integrity of struct ShowDescription

Title     string    `json:"title" yaml:"title" binding:"required"`          // REQUIRED 'channel.title' 'channel.itunes.title'
Summary   string    `json:"summary" yaml:"summary" binding:"required"`      // REQUIRED 'channel.description'
Link      Resource  `json:"link" yaml:"link"`                               // RECOMMENDED 'channel.link'
Category  Category  `json:"category" yaml:"category" binding:"required"`    // REQUIRED channel.category
Owner     Owner     `json:"owner" yaml:"owner"`                             // RECOMMENDED 'channel.itunes.owner'
Author    string    `json:"author" yaml:"author"`                           // RECOMMENDED 'channel.itunes.author'
Copyright string    `json:"copyright,omitempty" yaml:"copyright,omitempty"` // OPTIONAL 'channel.copyright'
NewFeed   *Resource `json:"newFeed,omitempty" yaml:"newFeed,omitempty"`     // OPTIONAL channel.itunes.new-feed-url -> move to label

type StatusObject added in v0.9.10

type StatusObject struct {
	Status    int    `json:"status" binding:"required"`
	Message   string `json:"message" binding:"required"`
	RootError error  `json:"-"`
}

StatusObject is used to report operation status and errors in an API request. The struct can be used as a response object or be treated as an error object

func NewErrorStatus added in v0.9.10

func NewErrorStatus(s int, e error) StatusObject

NewErrorStatus initializes a new StatusObject from an error

func NewStatus added in v0.9.10

func NewStatus(s int, m string) StatusObject

NewStatus initializes a new StatusObject

func (*StatusObject) Error added in v0.9.10

func (so *StatusObject) Error() string

Directories

Path Synopsis
cmd
api command
cdn command
cli command
rss
internal
cli

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL