mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-09 22:38:10 -05:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe0a173166 | ||
|
|
a916137db3 | ||
|
|
333c8cd363 | ||
|
|
294a4635de | ||
|
|
a70431eaa5 | ||
|
|
ac57c3d2b0 | ||
|
|
5e4e4f4bf1 | ||
|
|
96225d4aea | ||
|
|
adcdc0cf0b | ||
|
|
e3f9b12fde | ||
|
|
7fa4c0a030 | ||
|
|
8a3fa9337c |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,5 +1,32 @@
|
||||
# Changelog
|
||||
|
||||
## v1.4.355 (2025-12-20)
|
||||
|
||||
### PR [#1890](https://github.com/danielmiessler/Fabric/pull/1890) by [ksylvan](https://github.com/ksylvan): Bundle yt-dlp with fabric in Nix flake, introduce slim variant
|
||||
|
||||
- Added yt-dlp bundling with fabric package and introduced fabric-slim variant
|
||||
- Renamed original fabric package to fabricSlim and created new fabric package as symlinkJoin of fabricSlim and yt-dlp
|
||||
- Added fabric-slim output for the slim variant and updated default package to point to bundled fabric
|
||||
- Enhanced fabric meta description to note yt-dlp inclusion and set mainProgram to fabric in bundled package
|
||||
- Added wrapper for fabric binary to include PATH in execution environment
|
||||
|
||||
## v1.4.354 (2025-12-19)
|
||||
|
||||
### PR [#1889](https://github.com/danielmiessler/Fabric/pull/1889) by [ksylvan](https://github.com/ksylvan): docs: Add a YouTube transcript endpoint to the 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
|
||||
|
||||
## v1.4.353 (2025-12-19)
|
||||
|
||||
### PR [#1887](https://github.com/danielmiessler/Fabric/pull/1887) by [bvandevliet](https://github.com/bvandevliet): feat: correct video title and added description to yt transcript api response
|
||||
|
||||
- Feat: correct video title (instead of id) and added description to yt transcript api response
|
||||
- Updated API documentation.
|
||||
|
||||
## v1.4.352 (2025-12-18)
|
||||
|
||||
### PR [#1886](https://github.com/danielmiessler/Fabric/pull/1886) by [ksylvan](https://github.com/ksylvan): Enhanced Onboarding and Setup Experience
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var version = "v1.4.352"
|
||||
var version = "v1.4.355"
|
||||
|
||||
Binary file not shown.
105
docs/docs.go
105
docs/docs.go
@@ -214,6 +214,63 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/youtube/transcript": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Retrieves the transcript of a YouTube video along with video metadata (title and description)",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"youtube"
|
||||
],
|
||||
"summary": "Get YouTube video transcript",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "YouTube transcript request with URL, language, and timestamp options",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/restapi.YouTubeRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response with transcript and metadata",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/restapi.YouTubeResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request - invalid URL or playlist URL provided",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error - failed to retrieve transcript or metadata",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@@ -401,6 +458,54 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"restapi.YouTubeRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"language": {
|
||||
"description": "Language code for transcript (default: \"en\")",
|
||||
"type": "string",
|
||||
"example": "en"
|
||||
},
|
||||
"timestamps": {
|
||||
"description": "Include timestamps in the transcript (default: false)",
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"url": {
|
||||
"description": "YouTube video URL (required)",
|
||||
"type": "string",
|
||||
"example": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"restapi.YouTubeResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"description": "Video description from YouTube metadata",
|
||||
"type": "string",
|
||||
"example": "This is the video description from YouTube..."
|
||||
},
|
||||
"title": {
|
||||
"description": "Video title from YouTube metadata",
|
||||
"type": "string",
|
||||
"example": "Example Video Title"
|
||||
},
|
||||
"transcript": {
|
||||
"description": "The video transcript text",
|
||||
"type": "string",
|
||||
"example": "This is the video transcript..."
|
||||
},
|
||||
"videoId": {
|
||||
"description": "YouTube video ID",
|
||||
"type": "string",
|
||||
"example": "dQw4w9WgXcQ"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
|
||||
@@ -278,7 +278,9 @@ Extract transcripts from YouTube videos.
|
||||
|
||||
```json
|
||||
{
|
||||
"videoId": "Video ID",
|
||||
"title": "Video Title",
|
||||
"description" : "Video description...",
|
||||
"transcript": "Full transcript text..."
|
||||
}
|
||||
```
|
||||
@@ -335,7 +337,9 @@ Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"videoId": "dQw4w9WgXcQ",
|
||||
"title": "Rick Astley - Never Gonna Give You Up (Official Video)",
|
||||
"description": "The official video for “Never Gonna Give You Up” by Rick Astley...",
|
||||
"transcript": "We're no strangers to love. You know the rules and so do I..."
|
||||
}
|
||||
```
|
||||
|
||||
@@ -208,6 +208,63 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/youtube/transcript": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Retrieves the transcript of a YouTube video along with video metadata (title and description)",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"youtube"
|
||||
],
|
||||
"summary": "Get YouTube video transcript",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "YouTube transcript request with URL, language, and timestamp options",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/restapi.YouTubeRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response with transcript and metadata",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/restapi.YouTubeResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request - invalid URL or playlist URL provided",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error - failed to retrieve transcript or metadata",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@@ -395,6 +452,54 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"restapi.YouTubeRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"language": {
|
||||
"description": "Language code for transcript (default: \"en\")",
|
||||
"type": "string",
|
||||
"example": "en"
|
||||
},
|
||||
"timestamps": {
|
||||
"description": "Include timestamps in the transcript (default: false)",
|
||||
"type": "boolean",
|
||||
"example": false
|
||||
},
|
||||
"url": {
|
||||
"description": "YouTube video URL (required)",
|
||||
"type": "string",
|
||||
"example": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"restapi.YouTubeResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"description": "Video description from YouTube metadata",
|
||||
"type": "string",
|
||||
"example": "This is the video description from YouTube..."
|
||||
},
|
||||
"title": {
|
||||
"description": "Video title from YouTube metadata",
|
||||
"type": "string",
|
||||
"example": "Example Video Title"
|
||||
},
|
||||
"transcript": {
|
||||
"description": "The video transcript text",
|
||||
"type": "string",
|
||||
"example": "This is the video transcript..."
|
||||
},
|
||||
"videoId": {
|
||||
"description": "YouTube video ID",
|
||||
"type": "string",
|
||||
"example": "dQw4w9WgXcQ"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
|
||||
@@ -127,6 +127,42 @@ definitions:
|
||||
description: '"content", "error", "complete"'
|
||||
type: string
|
||||
type: object
|
||||
restapi.YouTubeRequest:
|
||||
properties:
|
||||
language:
|
||||
description: 'Language code for transcript (default: "en")'
|
||||
example: en
|
||||
type: string
|
||||
timestamps:
|
||||
description: 'Include timestamps in the transcript (default: false)'
|
||||
example: false
|
||||
type: boolean
|
||||
url:
|
||||
description: YouTube video URL (required)
|
||||
example: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
type: object
|
||||
restapi.YouTubeResponse:
|
||||
properties:
|
||||
description:
|
||||
description: Video description from YouTube metadata
|
||||
example: This is the video description from YouTube...
|
||||
type: string
|
||||
title:
|
||||
description: Video title from YouTube metadata
|
||||
example: Example Video Title
|
||||
type: string
|
||||
transcript:
|
||||
description: The video transcript text
|
||||
example: This is the video transcript...
|
||||
type: string
|
||||
videoId:
|
||||
description: YouTube video ID
|
||||
example: dQw4w9WgXcQ
|
||||
type: string
|
||||
type: object
|
||||
host: localhost:8080
|
||||
info:
|
||||
contact:
|
||||
@@ -262,6 +298,44 @@ paths:
|
||||
summary: Apply pattern with variables
|
||||
tags:
|
||||
- patterns
|
||||
/youtube/transcript:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Retrieves the transcript of a YouTube video along with video metadata
|
||||
(title and description)
|
||||
parameters:
|
||||
- description: YouTube transcript request with URL, language, and timestamp
|
||||
options
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/restapi.YouTubeRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response with transcript and metadata
|
||||
schema:
|
||||
$ref: '#/definitions/restapi.YouTubeResponse'
|
||||
"400":
|
||||
description: Bad request - invalid URL or playlist URL provided
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"500":
|
||||
description: Internal server error - failed to retrieve transcript or metadata
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get YouTube video transcript
|
||||
tags:
|
||||
- youtube
|
||||
securityDefinitions:
|
||||
ApiKeyAuth:
|
||||
in: header
|
||||
|
||||
27
flake.nix
27
flake.nix
@@ -73,14 +73,33 @@
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
goVersion = getGoVersion system;
|
||||
in
|
||||
{
|
||||
default = self.packages.${system}.fabric;
|
||||
fabric = pkgs.callPackage ./nix/pkgs/fabric {
|
||||
fabricSlim = pkgs.callPackage ./nix/pkgs/fabric {
|
||||
go = goVersion;
|
||||
inherit self;
|
||||
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
|
||||
};
|
||||
fabric = pkgs.symlinkJoin {
|
||||
name = "fabric-${fabricSlim.version}";
|
||||
inherit (fabricSlim) version;
|
||||
paths = [
|
||||
fabricSlim
|
||||
pkgs.yt-dlp
|
||||
];
|
||||
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||
postBuild = ''
|
||||
wrapProgram $out/bin/fabric \
|
||||
--prefix PATH : $out/bin
|
||||
'';
|
||||
meta = fabricSlim.meta // {
|
||||
description = "${fabricSlim.meta.description} (includes yt-dlp)";
|
||||
mainProgram = "fabric";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
default = fabric;
|
||||
inherit fabric;
|
||||
"fabric-slim" = fabricSlim;
|
||||
inherit (gomod2nix.legacyPackages.${system}) gomod2nix;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -12,15 +12,19 @@ type YouTubeHandler struct {
|
||||
yt *youtube.YouTube
|
||||
}
|
||||
|
||||
// YouTubeRequest represents a request to get a YouTube video transcript
|
||||
type YouTubeRequest struct {
|
||||
URL string `json:"url"`
|
||||
Language string `json:"language"`
|
||||
Timestamps bool `json:"timestamps"`
|
||||
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"`
|
||||
Title string `json:"title"`
|
||||
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 {
|
||||
@@ -29,6 +33,18 @@ func NewYouTubeHandler(r *gin.Engine, registry *core.PluginRegistry) *YouTubeHan
|
||||
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 {
|
||||
@@ -55,6 +71,20 @@ func (h *YouTubeHandler) Transcript(c *gin.Context) {
|
||||
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)
|
||||
@@ -66,5 +96,5 @@ func (h *YouTubeHandler) Transcript(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, YouTubeResponse{Transcript: transcript, Title: videoID})
|
||||
c.JSON(http.StatusOK, YouTubeResponse{Transcript: transcript, VideoId: videoID, Title: title, Description: description})
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
"1.4.352"
|
||||
"1.4.355"
|
||||
|
||||
Reference in New Issue
Block a user