mirror of
https://github.com/fiatjaf/nak.git
synced 2026-09-13 22:25:06 +00:00
Merge pull request #212 from mattn/feat/podcast-episode-prefix
podcast: show episode ids in 'list' and let 'play' take an id prefix
This commit is contained in:
+78
-7
@@ -31,7 +31,7 @@ var podcast = &cli.Command{
|
||||
{
|
||||
Name: "play",
|
||||
Usage: "play latest episode from podcast or specific episode",
|
||||
ArgsUsage: "<pubkey|nip05|npub|nprofile|nevent>",
|
||||
ArgsUsage: "<pubkey|nip05|npub|nprofile|nevent> [episode-id-prefix]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "relay",
|
||||
@@ -44,6 +44,28 @@ var podcast = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(ctx context.Context, c *cli.Command) error {
|
||||
// a second argument is the id prefix of an episode, as printed by
|
||||
// "podcast list"; otherwise the latest episode is played
|
||||
if c.Args().Len() == 2 {
|
||||
relays := c.StringSlice("relay")
|
||||
if err := normalizeAndValidateRelayURLs(relays); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pk, extraRelays, err := resolvePodcastPubKeyTarget(ctx, c.Args().Get(0))
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid podcast target %q: %w", c.Args().Get(0), err)
|
||||
}
|
||||
|
||||
episode, err := fetchPodcastEpisodeByPrefix(ctx,
|
||||
pk, c.Args().Get(1), nostr.AppendUnique(relays, extraRelays...), 500)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return playPodcastEpisode(c.String("player"), episode)
|
||||
}
|
||||
|
||||
for target := range getStdinLinesOrArguments(c.Args()) {
|
||||
if target == "" {
|
||||
return fmt.Errorf("missing podcast or episode target")
|
||||
@@ -224,11 +246,27 @@ func fetchSpecificPodcastEpisode(ctx context.Context, pointer nostr.EventPointer
|
||||
}
|
||||
|
||||
func fetchLatestEpisodeForPodcastSelection(ctx context.Context, pk nostr.PubKey, relayHints []string) (*nostr.Event, error) {
|
||||
choices, err := discoverPodcasts(ctx, pk, relayHints)
|
||||
chosen, err := selectPodcast(ctx, pk, relayHints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
episode, err := fetchLatestPodcastEpisode(ctx, chosen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return episode, nil
|
||||
}
|
||||
|
||||
// selectPodcast finds the podcasts published or listed by the given pubkey,
|
||||
// asking which one is meant when there is more than one.
|
||||
func selectPodcast(ctx context.Context, pk nostr.PubKey, relayHints []string) (podcastInfo, error) {
|
||||
choices, err := discoverPodcasts(ctx, pk, relayHints)
|
||||
if err != nil {
|
||||
return podcastInfo{}, err
|
||||
}
|
||||
|
||||
chosen := choices[0]
|
||||
if len(choices) > 1 {
|
||||
labels := make([]string, len(choices))
|
||||
@@ -242,7 +280,7 @@ func fetchLatestEpisodeForPodcastSelection(ctx context.Context, pk nostr.PubKey,
|
||||
Options: labels,
|
||||
PageSize: 12,
|
||||
}, &selected); err != nil {
|
||||
return nil, err
|
||||
return podcastInfo{}, err
|
||||
}
|
||||
|
||||
for i, label := range labels {
|
||||
@@ -253,12 +291,44 @@ func fetchLatestEpisodeForPodcastSelection(ctx context.Context, pk nostr.PubKey,
|
||||
}
|
||||
}
|
||||
|
||||
episode, err := fetchLatestPodcastEpisode(ctx, chosen)
|
||||
return chosen, nil
|
||||
}
|
||||
|
||||
// fetchPodcastEpisodeByPrefix finds one episode of the podcast by the id prefix
|
||||
// shown by "podcast list".
|
||||
func fetchPodcastEpisodeByPrefix(ctx context.Context, pk nostr.PubKey, prefix string, relayHints []string, limit int) (*nostr.Event, error) {
|
||||
prefix = strings.ToLower(strings.TrimSpace(prefix))
|
||||
if prefix == "" {
|
||||
return nil, fmt.Errorf("missing episode id prefix")
|
||||
}
|
||||
|
||||
chosen, err := selectPodcast(ctx, pk, relayHints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return episode, nil
|
||||
episodes, err := fetchPodcastEpisodes(ctx, chosen, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var matched *nostr.Event
|
||||
count := 0
|
||||
for _, ep := range episodes {
|
||||
if strings.HasPrefix(ep.ID.Hex(), prefix) {
|
||||
matched = &ep
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case count == 0:
|
||||
return nil, fmt.Errorf("no episode found with id prefix '%s'", prefix)
|
||||
case count > 1:
|
||||
return nil, fmt.Errorf("id prefix '%s' is ambiguous", prefix)
|
||||
}
|
||||
|
||||
return matched, nil
|
||||
}
|
||||
|
||||
func discoverPodcasts(ctx context.Context, pk nostr.PubKey, relayHints []string) ([]podcastInfo, error) {
|
||||
@@ -590,11 +660,12 @@ func printPodcastEpisodeList(ctx context.Context, p podcastInfo, limit int) erro
|
||||
for _, ep := range episodes {
|
||||
title := podcastTagValue(ep, "title")
|
||||
if title == "" {
|
||||
title = ep.ID.Hex()[:16]
|
||||
title = "<untitled>"
|
||||
}
|
||||
id := ep.ID.Hex()[:8]
|
||||
date := ep.CreatedAt.Time().Format("2006-01-02")
|
||||
desc := clampWithEllipsis(ep.Content, 100)
|
||||
stdout(fmt.Sprintf("%s %s %s", date, title, desc))
|
||||
stdout(fmt.Sprintf("%s %s %s %s", color.CyanString(id), date, title, desc))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user