diff --git a/main.go b/main.go index 165670e..16e3a87 100644 --- a/main.go +++ b/main.go @@ -195,6 +195,16 @@ func pollYouTube(feed config.Feed, sm *state.Manager, jobs chan<- downloader.Dow continue } + // YouTube Shorts are not podcast content: record as skipped so they + // are never downloaded and never re-resolved. + if info.MediaType == "short" { + dp := computeYTDestPath(feed.OutputDir, info.UploadDate, info.Title, v.ID) + if sm.AddJobWithStatus(feed.URL, watchURL(v.ID), dp, state.StatusSkipped, info.Duration) { + skipped++ + } + continue + } + // Out of the start_date window. Record as skipped so it isn't // re-resolved next poll. (Channel video order is not reliably // newest-first — e.g. the Iron Culture channel lists recent episodes diff --git a/ytdlp/ytdlp.go b/ytdlp/ytdlp.go index 3c204aa..a121ad5 100644 --- a/ytdlp/ytdlp.go +++ b/ytdlp/ytdlp.go @@ -81,6 +81,8 @@ type VideoInfo struct { Title string Duration float64 // seconds, 0 if unknown UploadDate time.Time + // MediaType is "video", "short", or "livestream" ("" if unknown). + MediaType string LiveStatus string // "not_live", "is_live", "was_live", "is_upcoming", or "" if unknown // ReleaseTimestamp is the scheduled start time of a live stream in unix // seconds (from liveBroadcastDetails.startTimestamp); 0 if unknown. @@ -129,6 +131,7 @@ func Info(ctx context.Context, s Settings, videoID string) (VideoInfo, error) { } } info.LiveStatus, _ = data["live_status"].(string) + info.MediaType, _ = data["media_type"].(string) if ts, ok := num(data["release_timestamp"]); ok { info.ReleaseTimestamp = int64(ts) }