more youtube metadata

This commit is contained in:
Erik Winter 2023-05-31 16:27:35 +02:00
parent b8c10a9d58
commit 82d95e98c9
8 changed files with 87 additions and 57 deletions

View File

@ -197,8 +197,11 @@ func (f *Fetcher) MetadataFetcher() {
continue continue
} }
for _, video := range videos { for _, video := range videos {
video.Title = mds[video.YoutubeID].Title md := mds[video.YoutubeID]
video.Description = mds[video.YoutubeID].Description video.YoutubeTitle = md.Title
video.YoutubeDescription = md.Description
video.YoutubeDuration = md.Duration
video.YoutubePublishedAt = md.PublishedAt
video.Status = model.StatusHasMetadata video.Status = model.StatusHasMetadata
if err := f.videoRepo.Save(video); err != nil { if err := f.videoRepo.Save(video); err != nil {

View File

@ -5,6 +5,8 @@ import "ewintr.nl/yogai/model"
type Metadata struct { type Metadata struct {
Title string Title string
Description string Description string
Duration string
PublishedAt string
} }
type MetadataFetcher interface { type MetadataFetcher interface {

View File

@ -2,8 +2,9 @@ package fetcher
import ( import (
"context" "context"
"ewintr.nl/yogai/model"
"fmt" "fmt"
"ewintr.nl/yogai/model"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
) )
@ -34,7 +35,7 @@ func (o *OpenAI) FetchSummary(video *model.Video) error {
{ {
Role: openai.ChatMessageRoleUser, Role: openai.ChatMessageRoleUser,
Content: fmt.Sprintf("%s\n\n%s", video.Title, video.Description), Content: fmt.Sprintf("%s\n\n%s", video.YoutubeTitle, video.YoutubeDescription),
}, },
}, },
}) })

View File

@ -46,7 +46,7 @@ func (y *Youtube) FetchMetadata(ytIDs []model.YoutubeVideoID) (map[model.Youtube
strIDs[i] = string(id) strIDs[i] = string(id)
} }
call := y.Client.Videos. call := y.Client.Videos.
List([]string{"snippet"}). List([]string{"snippet,contentDetails"}).
Id(strings.Join(strIDs, ",")) Id(strings.Join(strIDs, ","))
response, err := call.Do() response, err := call.Do()
@ -56,10 +56,20 @@ func (y *Youtube) FetchMetadata(ytIDs []model.YoutubeVideoID) (map[model.Youtube
mds := make(map[model.YoutubeVideoID]Metadata, len(response.Items)) mds := make(map[model.YoutubeVideoID]Metadata, len(response.Items))
for _, item := range response.Items { for _, item := range response.Items {
mds[model.YoutubeVideoID(item.Id)] = Metadata{ if item.Snippet == nil {
continue
}
md := Metadata{
Title: item.Snippet.Title, Title: item.Snippet.Title,
Description: item.Snippet.Description, Description: item.Snippet.Description,
PublishedAt: item.Snippet.PublishedAt,
} }
if item.ContentDetails != nil {
md.Duration = item.ContentDetails.Duration
}
mds[model.YoutubeVideoID(item.Id)] = md
} }
return mds, nil return mds, nil

View File

@ -50,7 +50,7 @@ func (v *VideoAPI) List(w http.ResponseWriter, r *http.Request) {
for _, v := range video { for _, v := range video {
resp = append(resp, respVideo{ resp = append(resp, respVideo{
YoutubeID: string(v.YoutubeID), YoutubeID: string(v.YoutubeID),
Title: v.Title, Title: v.YoutubeTitle,
Summary: v.Summary, Summary: v.Summary,
}) })
} }

View File

@ -16,11 +16,14 @@ type YoutubeVideoID string
type YoutubeChannelID string type YoutubeChannelID string
type Video struct { type Video struct {
ID uuid.UUID ID uuid.UUID
Status VideoStatus Status VideoStatus
YoutubeID YoutubeVideoID YoutubeID YoutubeVideoID
YoutubeChannelID YoutubeChannelID YoutubeChannelID YoutubeChannelID
Title string YoutubeTitle string
Description string YoutubeDescription string
Summary string YoutubeDuration string
YoutubePublishedAt string
Summary string
} }

45
storage/migrations.go Normal file
View File

@ -0,0 +1,45 @@
package storage
var pgMigration = []string{
`CREATE TYPE video_status AS ENUM ('new', 'ready')`,
`CREATE TABLE video (
id uuid PRIMARY KEY,
status video_status NOT NULL,
youtube_id VARCHAR(255) NOT NULL UNIQUE,
title VARCHAR(255) NOT NULL,
feed_id VARCHAR(255) NOT NULL,
description TEXT,
summary TEXT
)`,
`CREATE TYPE video_status_new AS ENUM ('new', 'has_metadata', 'has_summary', 'ready')`,
`ALTER TABLE video
ALTER COLUMN status TYPE video_status_new
USING video::text::video_status_new`,
`DROP TYPE video_status`,
`ALTER TYPE video_status_new RENAME TO video_status`,
`UPDATE video SET summary = '' WHERE summary IS NULL `,
`UPDATE video SET description = '' WHERE description IS NULL `,
`ALTER TABLE video
ALTER COLUMN summary SET DEFAULT '',
ALTER COLUMN summary SET NOT NULL,
ALTER COLUMN description SET DEFAULT '',
ALTER COLUMN description SET NOT NULL`,
`CREATE TYPE feed_status AS ENUM ('new', 'ready')`,
`CREATE TABLE feed (
id uuid PRIMARY KEY,
status feed_status NOT NULL,
youtube_channel_id VARCHAR(255) NOT NULL UNIQUE,
title VARCHAR(255) NOT NULL
)`,
`ALTER TABLE video
DROP COLUMN feed_id,
ADD COLUMN youtube_channel_id VARCHAR(255) NOT NULL REFERENCES feed(youtube_channel_id)`,
`ALTER TABLE video
ADD COLUMN duration VARCHAR(255),
ADD COLUMN published_at VARCHAR(255)`,
`ALTER TABLE video RENAME COLUMN duration TO youtube_duration`,
`ALTER TABLE video RENAME COLUMN published_at TO youtube_published_id`,
`ALTER TABLE video RENAME COLUMN title TO youtube_title`,
`ALTER TABLE video RENAME COLUMN description TO youtube_description`,
`ALTER TABLE video RENAME COLUMN youtube_published_id TO youtube_published_at`,
}

View File

@ -44,24 +44,26 @@ func NewPostgresVideoRepository(postgres *Postgres) *PostgresVideoRepository {
} }
func (p *PostgresVideoRepository) Save(v *model.Video) error { func (p *PostgresVideoRepository) Save(v *model.Video) error {
query := `INSERT INTO video (id, status, youtube_id, youtube_channel_id, title, description, summary) query := `INSERT INTO video (id, status, youtube_id, youtube_channel_id, youtube_title, youtube_description, youtube_duration, youtube_published_at, summary)
VALUES ($1, $2, $3, $4, $5, $6, $7) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
ON CONFLICT (id) ON CONFLICT (id)
DO UPDATE SET DO UPDATE SET
id = EXCLUDED.id, id = EXCLUDED.id,
status = EXCLUDED.status, status = EXCLUDED.status,
youtube_id = EXCLUDED.youtube_id, youtube_id = EXCLUDED.youtube_id,
youtube_channel_id = EXCLUDED.youtube_channel_id, youtube_channel_id = EXCLUDED.youtube_channel_id,
title = EXCLUDED.title, youtube_title = EXCLUDED.youtube_title,
description = EXCLUDED.description, youtube_description = EXCLUDED.youtube_description,
youtube_duration = EXCLUDED.youtube_duration,
youtube_published_at = EXCLUDED.youtube_published_at,
summary = EXCLUDED.summary;` summary = EXCLUDED.summary;`
_, err := p.db.Exec(query, v.ID, v.Status, v.YoutubeID, v.YoutubeChannelID, v.Title, v.Description, v.Summary) _, err := p.db.Exec(query, v.ID, v.Status, v.YoutubeID, v.YoutubeChannelID, v.YoutubeTitle, v.YoutubeDescription, v.YoutubeDuration, v.YoutubePublishedAt, v.Summary)
return err return err
} }
func (p *PostgresVideoRepository) FindByStatus(statuses ...model.VideoStatus) ([]*model.Video, error) { func (p *PostgresVideoRepository) FindByStatus(statuses ...model.VideoStatus) ([]*model.Video, error) {
query := `SELECT id, status, youtube_channel_id, youtube_id, title, description, summary query := `SELECT id, status, youtube_channel_id, youtube_id, youtube_title, youtube_description,youtube_duration, youtube_published_at, summary
FROM video FROM video
WHERE status = ANY($1)` WHERE status = ANY($1)`
rows, err := p.db.Query(query, pq.Array(statuses)) rows, err := p.db.Query(query, pq.Array(statuses))
@ -72,7 +74,7 @@ WHERE status = ANY($1)`
videos := []*model.Video{} videos := []*model.Video{}
for rows.Next() { for rows.Next() {
v := &model.Video{} v := &model.Video{}
if err := rows.Scan(&v.ID, &v.Status, &v.YoutubeChannelID, &v.YoutubeID, &v.Title, &v.Description, &v.Summary); err != nil { if err := rows.Scan(&v.ID, &v.Status, &v.YoutubeChannelID, &v.YoutubeID, &v.YoutubeTitle, &v.YoutubeDescription, &v.YoutubeDuration, &v.YoutubePublishedAt, &v.Summary); err != nil {
return nil, err return nil, err
} }
videos = append(videos, v) videos = append(videos, v)
@ -126,42 +128,6 @@ WHERE status = ANY($1)`
return feeds, nil return feeds, nil
} }
var pgMigration = []string{
`CREATE TYPE video_status AS ENUM ('new', 'ready')`,
`CREATE TABLE video (
id uuid PRIMARY KEY,
status video_status NOT NULL,
youtube_id VARCHAR(255) NOT NULL UNIQUE,
title VARCHAR(255) NOT NULL,
feed_id VARCHAR(255) NOT NULL,
description TEXT,
summary TEXT
)`,
`CREATE TYPE video_status_new AS ENUM ('new', 'has_metadata', 'has_summary', 'ready')`,
`ALTER TABLE video
ALTER COLUMN status TYPE video_status_new
USING video::text::video_status_new`,
`DROP TYPE video_status`,
`ALTER TYPE video_status_new RENAME TO video_status`,
`UPDATE video SET summary = '' WHERE summary IS NULL `,
`UPDATE video SET description = '' WHERE description IS NULL `,
`ALTER TABLE video
ALTER COLUMN summary SET DEFAULT '',
ALTER COLUMN summary SET NOT NULL,
ALTER COLUMN description SET DEFAULT '',
ALTER COLUMN description SET NOT NULL`,
`CREATE TYPE feed_status AS ENUM ('new', 'ready')`,
`CREATE TABLE feed (
id uuid PRIMARY KEY,
status feed_status NOT NULL,
youtube_channel_id VARCHAR(255) NOT NULL UNIQUE,
title VARCHAR(255) NOT NULL
)`,
`ALTER TABLE video
DROP COLUMN feed_id,
ADD COLUMN youtube_channel_id VARCHAR(255) NOT NULL REFERENCES feed(youtube_channel_id)`,
}
func (p *Postgres) migrate(wanted []string) error { func (p *Postgres) migrate(wanted []string) error {
query := `CREATE TABLE IF NOT EXISTS migration query := `CREATE TABLE IF NOT EXISTS migration
("id" SERIAL PRIMARY KEY, "query" TEXT)` ("id" SERIAL PRIMARY KEY, "query" TEXT)`