ilof

package
v0.0.0-...-f25d48c Latest Latest
Warning

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

Go to latest
Published: Sep 6, 2023 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package ilof provides support code for the In Lieu of Fun site.

Index

Constants

View Source
const AcastFeedURL = "https://feeds.acast.com/public/shows/in-lieu-of-fun"

AcastFeedURL is the URL of the Acast RSS feed for ILoF.

View Source
const BaseURL = "https://inlieuof.fun"

BaseURL is the base URL of the production site.

Variables

View Source
var ErrNoUpdates = errors.New("no matching updates")

ErrNoUpdates is reported by TwitterUpdates when no updates are available.

View Source
var KnownUsers = map[string]bool{
	"benjaminwittes":  true,
	"brookingsinst":   true,
	"crowdcast":       true,
	"crowdcasthq":     true,
	"genevievedfr":    true,
	"inlieuoffunshow": true,
	"klonick":         true,
	"lawfareblog":     true,
	"nytimes":         true,
	"scottjshapiro":   true,
	"youtube":         true,
}

KnownUsers is the list of Twitter handles that should not be considered candidate guest names, when reading tweets about the show. Names here should be normalized to all-lowercase.

Functions

func AddOrUpdateGuests

func AddOrUpdateGuests(episode float64, path string, guests []*Guest) error

AddOrUpdateGuests updates the guest list at path for the listed guests on the specified episode. New entries are added if they do not already exist, matched by name. Otherwise, new episode entries are added to existing guests. If successful, the file at path is updated in place.

func ContainsWord

func ContainsWord(s, word string) bool

ContainsWord reports whether s contains word.

func ForEachEpisode

func ForEachEpisode(dir string, f func(path string, ep *Episode) error) error

ForEachEpisode calls f for each episode file in the given directory. If f reports an error, the traversal stops and that error is reported to the caller of ForEachEpisode.

func Similarity

func Similarity(a, b string) float64

Similarity computes a Otsuka-Ochiai coefficient for the words in a and b.

func Words

func Words(s string) []string

Words parses s into a bag of words. Words are separated by whitespace and normalized to lower-case.

func WriteEpisode

func WriteEpisode(path string, ep *Episode) error

WriteEpisode writes the specified episode to path, overwriting an existing file if it exists.

func YouTubeCaptionURL

func YouTubeCaptionURL(ctx context.Context, id string) (string, error)

YouTubeCaptionURL returns the URL of the captions for the specified video ID. It returns "" without error if the video exists but lacks captions.

func YouTubeVideoID

func YouTubeVideoID(s string) (string, bool)

YouTubeVideoID reports whether s is a YouTube video URL, and if so returns the value of its video ID (v) parameter.

Types

type AudioEpisode

type AudioEpisode struct {
	Title       string        `json:"title,omitempty"`
	Subtitle    string        `json:"subtitle,omitempty"`
	Description string        `json:"description,omitempty"`
	PageLink    string        `json:"pageLink,omitempty"`  // URL of the landing page for this episode
	FileLink    string        `json:"fileLink,omitempty"`  // URL of the audio file for this episode
	DescLinks   []string      `json:"descLinks,omitempty"` // URLs embedded in the description
	Published   time.Time     `json:"published,omitempty"` // when this episode was published
	Duration    time.Duration `json:"duration,omitempty"`  // episode duration
	RawDesc     string        `json:"rawDescription,omitempty"`
}

AudioEpisode represents metadata about an audio recording of an ILoF episode on Acast, distilled out of the public RSS feed for the show.

func LoadAcastFeed

func LoadAcastFeed(ctx context.Context, url string) ([]*AudioEpisode, error)

LoadAcastFeed fetches and parses the Acast RSS feed from url.

type Caption

type Caption struct {
	Start    float64 `xml:"start,attr" json:"startSec"`  // seconds since start
	Duration float64 `xml:"dur,attr" json:"durationSec"` // seconds duration
	Text     string  `xml:",chardata" json:"text"`       // decoded text
}

Caption is a single text caption.

type Date

type Date time.Time

A Date records the date when an episode aired or will air. It is encoded as a string in the format "YYYY-MM-DD".

func (Date) MarshalText

func (d Date) MarshalText() ([]byte, error)

MarshalText encodes a date as a string (used for JSON).

func (Date) MarshalYAML

func (d Date) MarshalYAML() (interface{}, error)

MarshalYAML encodes a date as a YAML string.

func (Date) String

func (d Date) String() string

func (*Date) UnmarshalText

func (d *Date) UnmarshalText(data []byte) error

UnmarshalText decodes a date from a string formatted "2006-01-02".

func (*Date) UnmarshalYAML

func (d *Date) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML decodes a date from a YAML string formatted "2006-01-02".

type Episode

type Episode struct {
	Episode      Label    `json:"episode"`
	Date         Date     `json:"airDate" yaml:"date"`
	Guests       []string `json:"guestNames,omitempty" yaml:"-"`
	Topics       string   `json:"topics,omitempty" yaml:"topics,omitempty"`
	CrowdcastURL string   `json:"crowdcastURL,omitempty" yaml:"crowdcast,omitempty"`
	YouTubeURL   string   `json:"youTubeURL,omitempty" yaml:"youtube,omitempty"`
	AcastURL     string   `json:"acastURL,omitempty" yaml:"acast,omitempty"`
	AudioFileURL string   `json:"audioFileURL,omitempty" yaml:"audio-file,omitempty"`
	Summary      string   `json:"summary,omitempty" yaml:"summary,omitempty"`
	Special      bool     `json:"special,omitempty" yaml:"special,omitempty"`
	Tags         []string `json:"tags,omitempty" yaml:"tags,flow,omitempty"`
	Links        []*Link  `json:"links,omitempty" yaml:"links,omitempty"`
	Detail       string   `json:"detail,omitempty" yaml:"-"`
}

An Episode records details about an episode of the webcast.

func AllEpisodes

func AllEpisodes(ctx context.Context) ([]*Episode, error)

AllEpisodes queries the site for all episodes.

func FetchEpisode

func FetchEpisode(ctx context.Context, num string) (*Episode, error)

FetchEpisode queries the site for the specified episode.

func LatestEpisode

func LatestEpisode(ctx context.Context) (*Episode, error)

LatestEpisode queries the site for the latest episode.

func LoadEpisode

func LoadEpisode(path string) (*Episode, error)

LoadEpisode loads an episode from the markdown file at path.

func (*Episode) AddTag

func (e *Episode) AddTag(tag string)

AddTag adds tag to the tags list for e, if it is not already present.

func (*Episode) HasTag

func (e *Episode) HasTag(tag string) bool

HasTag reports whether e has the specified tag.

type Guest

type Guest struct {
	Name     string    `yaml:"name"`
	Twitter  string    `yaml:"twitter,omitempty"`
	URL      string    `yaml:"url,omitempty"`
	Notes    string    `yaml:"notes,omitempty"`
	Episodes []float64 `yaml:"episodes,flow"`
}

A Guest gives the name and some links for a guest.

func (*Guest) OnEpisode

func (g *Guest) OnEpisode(ep float64) bool

OnEpisode reports whether g is a guest on the specified episode.

func (*Guest) String

func (g *Guest) String() string

type Label

type Label string

A Label holds the string encoding of an episode label, which can be either a number or a string.

func (Label) MarshalJSON

func (x Label) MarshalJSON() ([]byte, error)

MarshalJSON encodes a label to a JSON number or string.

func (Label) MarshalYAML

func (x Label) MarshalYAML() (interface{}, error)

MarshalYAML encodes a label as a YAML number or string.

func (Label) Number

func (x Label) Number() float64

Number returns the numeric value of x, or -1 if x is not numeric in form.

func (*Label) UnmarshalJSON

func (x *Label) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a label from a JSON number or string.

type Link struct {
	Title string `json:"title,omitempty" yaml:"title,omitempty"`
	URL   string `json:"url" yaml:"url"`
}

A Link records the title and URL of a hyperlink.

type Transcript

type Transcript struct {
	VideoID     string     `json:"videoID"`
	CaptionsURL string     `json:"captionsURL"`
	Captions    []*Caption `json:"captions"`
}

Transcript is the decoded format of a set of video captions.

func YouTubeCaptionData

func YouTubeCaptionData(ctx context.Context, url string) (*Transcript, error)

YouTubeCaptionData loads and parses the specified caption URL and returns the resulting caption.

type TwitterUpdate

type TwitterUpdate struct {
	TweetID   string    // the ID of the announcement tweet
	Date      time.Time // the date of the announcement
	AirDate   time.Time // the speculated air date
	YouTube   string    // if available, the YouTube stream link
	Crowdcast string    // if available, the Crowdcast stream link
	Guests    []*Guest  // if available, possible guest twitter handles
}

A TwitterUpdate reports data extracted from an episode announcement status on Twitter.

func TwitterUpdates

func TwitterUpdates(ctx context.Context, token string, since Date) ([]*TwitterUpdate, error)

TwitterUpdates queries Twitter for episode updates since the specified date. Updates (if any) are returned in order from oldest to newest.

type VideoInfo

type VideoInfo struct {
	ID           string    `json:"-"`
	PublishedAt  time.Time `json:"publishedAt"`
	ChannelID    string    `json:"channelId"`
	ChannelTitle string    `json:"channelTitle"`
	Title        string    `json:"title"`
	Description  string    `json:"description"`

	Reply json.RawMessage `json:"-"`
}

VideoInfo carries metadata about a YouTube video.

func YouTubeVideoInfo

func YouTubeVideoInfo(ctx context.Context, id, apiKey string) (*VideoInfo, error)

YouTubeVideoInfo returns metadata about the specified YouTube video ID.

Jump to

Keyboard shortcuts

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