Added metadata lookup to youtube helper

This commit is contained in:
Cory Sougstad
2024-12-31 15:31:17 -07:00
parent ff21c60661
commit b4b8b96260
4 changed files with 79 additions and 11 deletions

View File

@@ -211,7 +211,7 @@ yt() {
}
```
This also creates a `yt` alias that allows you to use `yt https://www.youtube.com/watch?v=4b0iet22VIk` to get your transcripts.
This also creates a `yt` alias that allows you to use `yt https://www.youtube.com/watch?v=4b0iet22VIk` to get transcripts, comments, and metadata.
#### Save your files in markdown using aliases
@@ -323,6 +323,7 @@ Application Options:
-y, --youtube= YouTube video "URL" to grab transcript, comments from it and send to chat
--transcript Grab transcript from YouTube video and send to chat (it used per default).
--comments Grab comments from YouTube video and send to chat
--metadata Grab metadata from YouTube video and send to chat
-g, --language= Specify the Language Code for the chat, e.g. -g=en -g=zh
-u, --scrape_url= Scrape website URL to markdown using Jina AI
-q, --scrape_question= Search question using Jina AI
@@ -474,16 +475,18 @@ alias pbpaste='xclip -selection clipboard -o'
## Web Interface
Fabric now includes a built-in web interface that provides a GUI alternative to the command-line interface and an out-of-the-box website for those who want to get started with web development or blogging.
You can use this app as a GUI interface for Fabric, a ready to go blog-site, or a website template for your own projects.
You can use this app as a GUI interface for Fabric, a ready to go blog-site, or a website template for your own projects.
The `web/src/lib/content` directory includes starter `.obsidian/` and `templates/` directories, allowing you to open up the `web/src/lib/content/` directory as an [Obsidian.md](https://obsidian.md) vault. You can place your posts in the posts directory when you're ready to publish.
The `web/src/lib/content` directory includes starter `.obsidian/` and `templates/` directories, allowing you to open up the `web/src/lib/content/` directory as an [Obsidian.md](https://obsidian.md) vault. You can place your posts in the posts directory when you're ready to publish.
### Installing
The GUI can be installed by navigating to the `web` directory and using `npm install`, `pnpm install`, or your favorite package manager. Then simply run the development server to start the app. 
The GUI can be installed by navigating to the `web` directory and using `npm install`, `pnpm install`, or your favorite package manager. Then simply run the development server to start the app.
_You will need to run fabric in a separate terminal with the `fabric --serve` command._
_You will need to run fabric in a separate terminal with the `fabric --serve` command._
**From the fabric project `web/` directory:**
```shell
npm run dev
@@ -491,7 +494,7 @@ npm run dev
pnpm run dev
## or your equivalent
## or your equivalent
```
### Streamlit UI
@@ -507,10 +510,12 @@ streamlit run streamlit.py
```
The Streamlit UI provides a user-friendly interface for:
- Running and chaining patterns
- Managing pattern outputs
- Creating and editing patterns
- Analyzing pattern results
## Meta
> [!NOTE]

View File

@@ -1,6 +1,7 @@
package cli
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
@@ -286,7 +287,7 @@ func Cli(version string) (err error) {
func processYoutubeVideo(
flags *Flags, registry *core.PluginRegistry, videoId string) (message string, err error) {
if !flags.YouTubeComments || flags.YouTubeTranscript {
if (!flags.YouTubeComments && !flags.YouTubeMetadata) || flags.YouTubeTranscript {
var transcript string
var language = "en"
if flags.Language != "" || registry.Language.DefaultLanguage.Value != "" {
@@ -312,6 +313,16 @@ func processYoutubeVideo(
message = AppendMessage(message, commentsString)
}
if flags.YouTubeMetadata {
var metadata *youtube.VideoMetadata
if metadata, err = registry.YouTube.GrabMetadata(videoId); err != nil {
return
}
metadataJson, _ := json.MarshalIndent(metadata, "", " ")
message = AppendMessage(message, string(metadataJson))
}
return
}

View File

@@ -47,8 +47,9 @@ type Flags struct {
ChangeDefaultModel bool `short:"d" long:"changeDefaultModel" description:"Change default model"`
YouTube string `short:"y" long:"youtube" description:"YouTube video or play list \"URL\" to grab transcript, comments from it and send to chat or print it put to the console and store it in the output file"`
YouTubePlaylist bool `long:"playlist" description:"Prefer playlist over video if both ids are present in the URL"`
YouTubeTranscript bool `long:"transcript" description:"Grab transcript from YouTube video and send to chat (it used per default)."`
YouTubeTranscript bool `long:"transcript" description:"Grab transcript from YouTube video and send to chat (it is used per default)."`
YouTubeComments bool `long:"comments" description:"Grab comments from YouTube video and send to chat"`
YouTubeMetadata bool `long:"metadata" description:"Output video metadata"`
Language string `short:"g" long:"language" description:"Specify the Language Code for the chat, e.g. -g=en -g=zh" default:""`
ScrapeURL string `short:"u" long:"scrape_url" description:"Scrape website URL to markdown using Jina AI"`
ScrapeQuestion string `short:"q" long:"scrape_question" description:"Search question using Jina AI"`

View File

@@ -238,6 +238,13 @@ func (o *YouTube) Grab(url string, options *Options) (ret *VideoInfo, err error)
ret = &VideoInfo{}
if options.Metadata {
if ret.Metadata, err = o.GrabMetadata(videoId); err != nil {
err = fmt.Errorf("error getting video metadata: %v", err)
return
}
}
if options.Duration {
if ret.Duration, err = o.GrabDuration(videoId); err != nil {
err = fmt.Errorf("error parsing video duration: %v", err)
@@ -369,12 +376,55 @@ type Options struct {
Transcript bool
Comments bool
Lang string
Metadata bool
}
type VideoInfo struct {
Transcript string `json:"transcript"`
Duration int `json:"duration"`
Comments []string `json:"comments"`
Transcript string `json:"transcript"`
Duration int `json:"duration"`
Comments []string `json:"comments"`
Metadata *VideoMetadata `json:"metadata,omitempty"`
}
type VideoMetadata struct {
Title string `json:"title"`
Description string `json:"description"`
PublishedAt string `json:"publishedAt"`
ChannelId string `json:"channelId"`
ChannelTitle string `json:"channelTitle"`
ViewCount uint64 `json:"viewCount"`
LikeCount uint64 `json:"likeCount"`
}
func (o *YouTube) GrabMetadata(videoId string) (metadata *VideoMetadata, err error) {
if err = o.initService(); err != nil {
return
}
call := o.service.Videos.List([]string{"snippet", "statistics"}).Id(videoId)
var response *youtube.VideoListResponse
if response, err = call.Do(); err != nil {
return nil, fmt.Errorf("error getting video metadata: %v", err)
}
if len(response.Items) == 0 {
return nil, fmt.Errorf("no video found with ID: %s", videoId)
}
video := response.Items[0]
viewCount := video.Statistics.ViewCount
likeCount := video.Statistics.LikeCount
metadata = &VideoMetadata{
Title: video.Snippet.Title,
Description: video.Snippet.Description,
PublishedAt: video.Snippet.PublishedAt,
ChannelId: video.Snippet.ChannelId,
ChannelTitle: video.Snippet.ChannelTitle,
ViewCount: viewCount,
LikeCount: likeCount,
}
return
}
func (o *YouTube) GrabByFlags() (ret *VideoInfo, err error) {
@@ -383,6 +433,7 @@ func (o *YouTube) GrabByFlags() (ret *VideoInfo, err error) {
flag.BoolVar(&options.Transcript, "transcript", false, "Output only the transcript")
flag.BoolVar(&options.Comments, "comments", false, "Output the comments on the video")
flag.StringVar(&options.Lang, "lang", "en", "Language for the transcript (default: English)")
flag.BoolVar(&options.Metadata, "metadata", false, "Output video metadata")
flag.Parse()
if flag.NArg() == 0 {