aboutsummaryrefslogtreecommitdiff
path: root/cmd/patchouli/main.go
diff options
context:
space:
mode:
authorXe Iaso <me@xeiaso.net>2025-01-07 23:41:53 -0500
committerXe Iaso <me@xeiaso.net>2025-01-11 16:46:28 -0500
commit6bc2938856792f851b18fb3550fdb4c2c8040fce (patch)
treee7a77aa35d9c94ae5ea7609c08f00b2b3ffca6eb /cmd/patchouli/main.go
parentc2187ae96bf081aba31a965d0b58e5934a42a93f (diff)
downloadx-6bc2938856792f851b18fb3550fdb4c2c8040fce.tar.xz
x-6bc2938856792f851b18fb3550fdb4c2c8040fce.zip
kube/alrest: fix
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'cmd/patchouli/main.go')
-rw-r--r--cmd/patchouli/main.go134
1 files changed, 134 insertions, 0 deletions
diff --git a/cmd/patchouli/main.go b/cmd/patchouli/main.go
new file mode 100644
index 0000000..a316a0c
--- /dev/null
+++ b/cmd/patchouli/main.go
@@ -0,0 +1,134 @@
+package main
+
+import (
+ "context"
+ "database/sql"
+ "flag"
+ "fmt"
+ "log"
+ "log/slog"
+ "net/http"
+ "path/filepath"
+
+ "connectrpc.com/connect"
+ _ "github.com/ncruces/go-sqlite3/embed"
+ "github.com/ncruces/go-sqlite3/gormlite"
+ slogGorm "github.com/orandin/slog-gorm"
+ "google.golang.org/protobuf/types/known/timestamppb"
+ "gorm.io/gorm"
+ gormPrometheus "gorm.io/plugin/prometheus"
+ "within.website/x/buf/patchouli"
+ "within.website/x/buf/patchouli/patchouliconnect"
+ "within.website/x/cmd/patchouli/ytdlp"
+ "within.website/x/internal"
+)
+
+var (
+ bind = flag.String("bind", ":2934", "HTTP bind address")
+ dataDir = flag.String("data-dir", "./var", "location to store data persistently")
+)
+
+func main() {
+ internal.HandleStartup()
+
+ slog.Info("starting up", "bind", *bind, "data-dir", *dataDir)
+
+ db, err := connectDB()
+ if err != nil {
+ log.Fatalf("can't connect to DB: %w", err)
+ }
+ _ = db
+
+ s := &Server{db: db}
+
+ compress1KB := connect.WithCompressMinBytes(1024)
+
+ mux := http.NewServeMux()
+ mux.Handle(patchouliconnect.NewSyndicateHandler(s, compress1KB))
+
+ slog.Info("listening", "url", "http://localhost"+*bind)
+ log.Fatal(http.ListenAndServe(*bind, mux))
+}
+
+func connectDB() (*gorm.DB, error) {
+ db, err := gorm.Open(gormlite.Open(filepath.Join(*dataDir, "data.db")), &gorm.Config{
+ Logger: slogGorm.New(
+ slogGorm.WithErrorField("err"),
+ slogGorm.WithRecordNotFoundError(),
+ ),
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to connect to database: %w", err)
+ }
+
+ if err := db.AutoMigrate(
+ &Video{},
+ ); err != nil {
+ return nil, fmt.Errorf("failed to migrate schema: %w", err)
+ }
+
+ db.Use(gormPrometheus.New(gormPrometheus.Config{
+ DBName: "mi",
+ }))
+
+ return db, nil
+}
+
+type Server struct {
+ db *gorm.DB
+}
+
+func (s *Server) Info(
+ ctx context.Context,
+ req *connect.Request[patchouli.TwitchInfoReq],
+) (
+ *connect.Response[patchouli.TwitchInfoResp],
+ error,
+) {
+ metadata, err := ytdlp.Metadata(ctx, req.Msg.GetUrl())
+ if err != nil {
+ slog.Error("can't fetch metadata for video", "url", req.Msg.GetUrl(), "err", err)
+ return nil, connect.NewError(connect.CodeInternal, err)
+ }
+
+ result := &patchouli.TwitchInfoResp{
+ Id: metadata.ID,
+ Title: metadata.Title,
+ ThumbnailUrl: metadata.Thumbnail,
+ Duration: metadata.DurationString,
+ UploadDate: timestamppb.New(metadata.UploadDate.Time),
+ Url: req.Msg.GetUrl(),
+ }
+
+ return connect.NewResponse(result), nil
+}
+
+func (s *Server) Download(
+ ctx context.Context,
+ req *connect.Request[patchouli.TwitchDownloadReq],
+) (
+ *connect.Response[patchouli.TwitchDownloadResp],
+ error,
+) {
+ dir := filepath.Join(*dataDir, "video")
+
+ if err := ytdlp.Download(ctx, req.Msg.GetUrl(), dir); err != nil {
+ return nil, err
+ }
+
+ result := &patchouli.TwitchDownloadResp{
+ Url: req.Msg.Url,
+ Location: dir,
+ }
+
+ return connect.NewResponse(result), nil
+}
+
+type Video struct {
+ gorm.Model
+ TwitchID string `gorm:"uniqueIndex"`
+ TwitchURL string `gorm:"uniqueIndex"`
+ Title string
+ State string
+ BlogPath sql.NullString
+}