Documentation
¶
Overview ¶
Package media provides media transcript retrieval via yt-dlp. It wraps yt-dlp for subtitle download, cleans VTT caption files to remove bloat from auto-generated subtitles, and stores transcripts durably as markdown files with YAML frontmatter.
Index ¶
- func CleanVTT(raw string) string
- func CleanVTTWithParagraphs(raw string) string
- func FeedsDefinition() map[string]any
- func FollowDefinition() map[string]any
- func SaveDefinition() map[string]any
- func ToolDefinition() map[string]any
- func ToolHandler(c *Client) func(ctx context.Context, args map[string]any) (string, error)
- func UnfollowDefinition() map[string]any
- type AnalysisPage
- type AnalysisTools
- type Client
- type Config
- type DetailLevel
- type Engagement
- type Feed
- type FeedEntry
- type FeedPoller
- type FeedTools
- func (ft *FeedTools) FeedsHandler() func(ctx context.Context, args map[string]any) (string, error)
- func (ft *FeedTools) FollowHandler() func(ctx context.Context, args map[string]any) (string, error)
- func (ft *FeedTools) UnfollowHandler() func(ctx context.Context, args map[string]any) (string, error)
- type MediaStore
- type Result
- type SummarizeFunc
- type VaultWriter
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CleanVTT ¶
CleanVTT takes raw VTT subtitle content and produces clean, readable plain text. The pipeline strips headers, timing lines, HTML tags, and deduplicates rolling caption lines that auto-generated subtitles repeat across overlapping segments. The result is typically 25-30% the size of the raw VTT input.
func CleanVTTWithParagraphs ¶
CleanVTTWithParagraphs is like CleanVTT but inserts paragraph breaks (double newlines) when the timing gap between consecutive cues exceeds 2 seconds. This produces more readable output for long transcripts where topic shifts align with speaker pauses.
func FeedsDefinition ¶ added in v0.8.0
FeedsDefinition returns the JSON Schema for the media_feeds tool.
func FollowDefinition ¶ added in v0.8.0
FollowDefinition returns the JSON Schema for the media_follow tool.
func SaveDefinition ¶ added in v0.8.0
SaveDefinition returns the JSON Schema for the media_save_analysis tool.
func ToolDefinition ¶
ToolDefinition returns the JSON Schema parameters for the media_transcript tool.
func ToolHandler ¶
ToolHandler returns a function compatible with the tools.Tool Handler signature. It wraps the Client for use as an agent tool.
func UnfollowDefinition ¶ added in v0.8.0
UnfollowDefinition returns the JSON Schema for the media_unfollow tool.
Types ¶
type AnalysisPage ¶ added in v0.8.0
type AnalysisPage struct {
Title string
Channel string
URL string
Published string // YYYY-MM-DD or empty (falls back to today)
Topics []string
TrustZone string
QualityScore float64
AnalyzedAt time.Time
Content string // Markdown body written by the agent
}
AnalysisPage holds the data for a single media analysis markdown file. The Content field is the agent-generated analysis body; everything else becomes YAML frontmatter.
type AnalysisTools ¶ added in v0.8.0
type AnalysisTools struct {
// contains filtered or unexported fields
}
AnalysisTools provides tool handlers for persisting media analysis to an Obsidian-compatible vault and tracking engagement.
func NewAnalysisTools ¶ added in v0.8.0
func NewAnalysisTools( state *opstate.Store, store *MediaStore, writer *VaultWriter, defaultOutputPath string, logger *slog.Logger, ) *AnalysisTools
NewAnalysisTools creates analysis tool handlers. The defaultOutputPath is used when a feed has no per-feed output_path configured.
func (*AnalysisTools) SaveHandler ¶ added in v0.8.0
func (at *AnalysisTools) SaveHandler() func(ctx context.Context, args map[string]any) (string, error)
SaveHandler returns the tool handler for media_save_analysis.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client retrieves and cleans media transcripts.
func New ¶
New creates a media transcript client. The yt-dlp binary path is resolved via Config.YtDlpPath or exec.LookPath.
func (*Client) GetTranscript ¶
func (c *Client) GetTranscript(ctx context.Context, rawURL, language, focus string, detail DetailLevel) (*Result, error)
GetTranscript fetches the transcript for the given media URL. It prefers manual subtitles over auto-generated, and falls back to Whisper transcription via Ollama when no subtitles are available.
The focus parameter, when non-empty, guides summarization to emphasize content related to the topic. The detail parameter controls processing: DetailFull returns the raw transcript, DetailSummary produces a map-reduce summary, and DetailBrief produces an aggressive ~500-char summary.
func (*Client) SetSummarizer ¶
func (c *Client) SetSummarizer(fn SummarizeFunc)
SetSummarizer configures the LLM summarization function used for map-reduce transcript processing. When nil, the client returns raw transcripts regardless of the requested detail level.
type Config ¶
type Config struct {
// YtDlpPath is the path to the yt-dlp binary. If empty, the binary
// is located via exec.LookPath.
YtDlpPath string
// CookiesFile is an optional path to a Netscape-format cookie file
// for accessing auth-required content.
CookiesFile string
// SubtitleLanguage is the preferred subtitle language code (default "en").
SubtitleLanguage string
// MaxTranscriptChars limits the transcript text returned in-context.
// Longer transcripts are truncated. Default: 50000.
MaxTranscriptChars int
// WhisperModel is the Ollama model name for audio transcription
// fallback when no subtitles are available (default "large-v3").
WhisperModel string
// TranscriptDir is the directory for durable transcript storage.
// Each transcript is saved as a markdown file with YAML frontmatter.
// If empty, transcripts are returned in-context only.
TranscriptDir string
// OllamaURL is the base URL for Ollama API calls (Whisper fallback).
OllamaURL string
}
Config holds settings for the media transcript client.
type DetailLevel ¶
type DetailLevel string
DetailLevel controls how much processing is applied to a transcript before it is returned to the caller.
const ( // DetailFull returns the raw cleaned transcript without summarization. DetailFull DetailLevel = "full" // DetailSummary produces a map-reduce summary of ~2000-3000 characters. DetailSummary DetailLevel = "summary" // DetailBrief produces an aggressive summary of ~500 characters. DetailBrief DetailLevel = "brief" )
type Engagement ¶ added in v0.8.0
type Engagement struct {
ID string
EntryURL string
FeedID string
AnalysisPath string
AnalysisDepth string
Topics []string
TrustZone string
QualityScore float64
Engaged bool
AnalyzedAt time.Time
SessionID string
}
Engagement records a media analysis event — what was analyzed, where the output was saved, and metadata for future interest prediction.
type Feed ¶ added in v0.8.0
Feed represents a parsed RSS or Atom feed with its entries normalized into a common structure.
type FeedEntry ¶ added in v0.8.0
type FeedEntry struct {
ID string // <guid> (RSS) or <id> (Atom)
Title string
Link string
Published time.Time
}
FeedEntry represents a single item in a feed.
type FeedPoller ¶ added in v0.8.0
type FeedPoller struct {
// contains filtered or unexported fields
}
FeedPoller checks followed RSS/Atom feeds for new entries by comparing entry IDs against a persisted high-water mark. It follows the same pattern as email.Poller — infrastructure code called by the scheduler task executor.
func NewFeedPoller ¶ added in v0.8.0
func NewFeedPoller(state *opstate.Store, logger *slog.Logger) *FeedPoller
NewFeedPoller creates a feed poller that checks all followed feeds and tracks state in the provided opstate store.
func (*FeedPoller) CheckFeeds ¶ added in v0.8.0
func (p *FeedPoller) CheckFeeds(ctx context.Context) (string, error)
CheckFeeds checks all followed feeds for new entries. Returns a formatted wake message describing new content, or empty string if nothing new was found. Network errors are logged and skipped per-feed; a failure on one feed does not prevent checking others.
type FeedTools ¶ added in v0.8.0
type FeedTools struct {
// contains filtered or unexported fields
}
FeedTools provides tool handlers and definitions for feed management.
func NewFeedTools ¶ added in v0.8.0
NewFeedTools creates a FeedTools instance. The HTTP client is created internally via httpkit.
func (*FeedTools) FeedsHandler ¶ added in v0.8.0
FeedsHandler returns the tool handler for media_feeds.
func (*FeedTools) FollowHandler ¶ added in v0.8.0
FollowHandler returns the tool handler for media_follow.
type MediaStore ¶ added in v0.8.0
type MediaStore struct {
// contains filtered or unexported fields
}
MediaStore persists media engagement records in SQLite. It tracks which content has been analyzed, enabling deduplication and (in future) interest prediction from engagement history.
func NewMediaStore ¶ added in v0.8.0
func NewMediaStore(dbPath string, logger *slog.Logger) (*MediaStore, error)
NewMediaStore opens (or creates) the engagement database at dbPath and runs migrations.
func (*MediaStore) Close ¶ added in v0.8.0
func (s *MediaStore) Close() error
Close closes the underlying database connection.
func (*MediaStore) HasBeenAnalyzed ¶ added in v0.8.0
HasBeenAnalyzed reports whether the given entry URL has already been analyzed. Used to avoid duplicate analysis on re-polls.
func (*MediaStore) RecordAnalysis ¶ added in v0.8.0
func (s *MediaStore) RecordAnalysis(ctx context.Context, e *Engagement) error
RecordAnalysis inserts an engagement record. If the Engagement has no ID, a new UUIDv7 is generated. If AnalyzedAt is zero, the current time is used.
type Result ¶
type Result struct {
Title string `json:"title"`
Channel string `json:"channel,omitempty"`
Duration string `json:"duration,omitempty"`
UploadDate string `json:"upload_date,omitempty"`
Description string `json:"description,omitempty"`
Transcript string `json:"transcript"`
Source string `json:"source"`
ID string `json:"id"`
TranscriptPath string `json:"transcript_path,omitempty"`
Truncated bool `json:"truncated,omitempty"`
Summarized bool `json:"summarized,omitempty"`
DetailLevel string `json:"detail_level,omitempty"`
Focus string `json:"focus,omitempty"`
AnalysisGuidance string `json:"analysis_guidance,omitempty"`
}
Result holds the fetched transcript and associated metadata.
type SummarizeFunc ¶
SummarizeFunc is a function that sends a prompt to an LLM and returns the response text. It decouples the media package from specific LLM and router implementations. The caller (typically cmd/thane/main.go) builds a closure that handles model selection and provider routing.
type VaultWriter ¶ added in v0.8.0
type VaultWriter struct {
// contains filtered or unexported fields
}
VaultWriter writes structured analysis markdown files to an Obsidian-compatible vault directory. Each channel gets a subdirectory under Channels/ with an auto-maintained _channel.md index file.
func NewVaultWriter ¶ added in v0.8.0
func NewVaultWriter(logger *slog.Logger) *VaultWriter
NewVaultWriter creates a vault writer.
func (*VaultWriter) WriteAnalysis ¶ added in v0.8.0
func (w *VaultWriter) WriteAnalysis(outputPath string, page *AnalysisPage) (string, error)
WriteAnalysis writes an analysis page to the vault and updates the channel index. Returns the path of the written file (absolute if outputPath is absolute).
Directory structure:
{outputPath}/Channels/{channel-slug}/{date}-{title-slug}-{hash}.md
{outputPath}/Channels/{channel-slug}/_channel.md