Files
Fabric/internal/server/youtube.go
Kayvan Sylvan 5e4e4f4bf1 docs: Add YouTube transcript endpoint to Swagger UI.
- Add `/youtube/transcript` POST endpoint to Swagger docs
- Define `YouTubeRequest` schema with URL, language, timestamps fields
- Define `YouTubeResponse` schema with transcript and metadata fields
- Add API security requirement using ApiKeyAuth
- Document 200, 400, and 500 response codes
- Add godoc comments to YouTubeHandler struct methods
- Include example values for all request/response properties
2025-12-19 10:41:55 -08:00

101 lines
3.9 KiB
Go

package restapi
import (
"net/http"
"github.com/danielmiessler/fabric/internal/core"
"github.com/danielmiessler/fabric/internal/tools/youtube"
"github.com/gin-gonic/gin"
)
type YouTubeHandler struct {
yt *youtube.YouTube
}
// YouTubeRequest represents a request to get a YouTube video transcript
type YouTubeRequest struct {
URL string `json:"url" binding:"required" example:"https://www.youtube.com/watch?v=dQw4w9WgXcQ"` // YouTube video URL (required)
Language string `json:"language,omitempty" example:"en"` // Language code for transcript (default: "en")
Timestamps bool `json:"timestamps,omitempty" example:"false"` // Include timestamps in the transcript (default: false)
}
// YouTubeResponse represents the response containing video transcript and metadata
type YouTubeResponse struct {
Transcript string `json:"transcript" example:"This is the video transcript..."` // The video transcript text
VideoId string `json:"videoId" example:"dQw4w9WgXcQ"` // YouTube video ID
Title string `json:"title" example:"Example Video Title"` // Video title from YouTube metadata
Description string `json:"description" example:"This is the video description from YouTube..."` // Video description from YouTube metadata
}
func NewYouTubeHandler(r *gin.Engine, registry *core.PluginRegistry) *YouTubeHandler {
handler := &YouTubeHandler{yt: registry.YouTube}
r.POST("/youtube/transcript", handler.Transcript)
return handler
}
// Transcript godoc
// @Summary Get YouTube video transcript
// @Description Retrieves the transcript of a YouTube video along with video metadata (title and description)
// @Tags youtube
// @Accept json
// @Produce json
// @Param request body YouTubeRequest true "YouTube transcript request with URL, language, and timestamp options"
// @Success 200 {object} YouTubeResponse "Successful response with transcript and metadata"
// @Failure 400 {object} map[string]string "Bad request - invalid URL or playlist URL provided"
// @Failure 500 {object} map[string]string "Internal server error - failed to retrieve transcript or metadata"
// @Security ApiKeyAuth
// @Router /youtube/transcript [post]
func (h *YouTubeHandler) Transcript(c *gin.Context) {
var req YouTubeRequest
if err := c.BindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
return
}
if req.URL == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "url is required"})
return
}
language := req.Language
if language == "" {
language = "en"
}
var videoID, playlistID string
var err error
if videoID, playlistID, err = h.yt.GetVideoOrPlaylistId(req.URL); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if videoID == "" && playlistID != "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "URL is a playlist, not a video"})
return
}
// Try to get metadata (requires valid YouTube API key), but don't fail if unavailable
// This allows the endpoint to work for transcript extraction even without API key
var metadata *youtube.VideoMetadata
var title, description string
if metadata, err = h.yt.GrabMetadata(videoID); err == nil {
// Metadata available - use title and description from API
title = metadata.Title
description = metadata.Description
} else {
// No valid API key or metadata fetch failed - fallback to videoID as title
title = videoID
description = ""
}
var transcript string
if req.Timestamps {
transcript, err = h.yt.GrabTranscriptWithTimestamps(videoID, language)
} else {
transcript, err = h.yt.GrabTranscript(videoID, language)
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, YouTubeResponse{Transcript: transcript, VideoId: videoID, Title: title, Description: description})
}