195 lines
4.2 KiB
Go
195 lines
4.2 KiB
Go
package rest
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/config"
|
|
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal"
|
|
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal/downloaders"
|
|
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal/kv"
|
|
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal/livestream"
|
|
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/internal/queue"
|
|
"github.com/marcopiovanello/yt-dlp-web-ui/v3/server/playlist"
|
|
|
|
bolt "go.etcd.io/bbolt"
|
|
)
|
|
|
|
type Service struct {
|
|
mdb *kv.Store
|
|
db *bolt.DB
|
|
mq *queue.MessageQueue
|
|
lm *livestream.Monitor
|
|
}
|
|
|
|
func NewService(
|
|
mdb *kv.Store,
|
|
db *bolt.DB,
|
|
mq *queue.MessageQueue,
|
|
lm *livestream.Monitor,
|
|
) *Service {
|
|
db.Update(func(tx *bolt.Tx) error {
|
|
_, err := tx.CreateBucketIfNotExists([]byte("templates"))
|
|
return err
|
|
})
|
|
return &Service{
|
|
mdb: mdb,
|
|
db: db,
|
|
mq: mq,
|
|
lm: lm,
|
|
}
|
|
}
|
|
|
|
func (s *Service) Exec(req internal.DownloadRequest) (string, error) {
|
|
d := downloaders.NewGenericDownload(req.URL, req.Params)
|
|
d.SetOutput(internal.DownloadOutput{
|
|
Path: req.Path,
|
|
Filename: req.Rename,
|
|
})
|
|
|
|
id := s.mdb.Set(d)
|
|
s.mq.Publish(d)
|
|
|
|
return id, nil
|
|
}
|
|
|
|
func (s *Service) ExecPlaylist(req internal.DownloadRequest) error {
|
|
return playlist.PlaylistDetect(req, s.mq, s.mdb)
|
|
}
|
|
|
|
func (s *Service) ExecLivestream(req internal.DownloadRequest) {
|
|
s.lm.Add(req.URL)
|
|
}
|
|
|
|
func (s *Service) Running(ctx context.Context) (*[]internal.ProcessSnapshot, error) {
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil, context.Canceled
|
|
default:
|
|
return s.mdb.All(), nil
|
|
}
|
|
}
|
|
|
|
func (s *Service) GetCookies(ctx context.Context) ([]byte, error) {
|
|
fd, err := os.Open("cookies.txt")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer fd.Close()
|
|
|
|
cookies, err := io.ReadAll(fd)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return cookies, nil
|
|
}
|
|
|
|
func (s *Service) SetCookies(ctx context.Context, cookies string) error {
|
|
fd, err := os.Create("cookies.txt")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer fd.Close()
|
|
fd.WriteString(cookies)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) SaveTemplate(ctx context.Context, template *internal.CustomTemplate) error {
|
|
return s.db.Update(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte("templates"))
|
|
v, err := json.Marshal(template)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return b.Put([]byte(uuid.NewString()), v)
|
|
})
|
|
}
|
|
|
|
func (s *Service) GetTemplates(ctx context.Context) (*[]internal.CustomTemplate, error) {
|
|
templates := make([]internal.CustomTemplate, 0)
|
|
|
|
err := s.db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte("templates"))
|
|
if b == nil {
|
|
return nil // bucket vuoto, restituisco lista vuota
|
|
}
|
|
|
|
return b.ForEach(func(k, v []byte) error {
|
|
var t internal.CustomTemplate
|
|
if err := json.Unmarshal(v, &t); err != nil {
|
|
return err
|
|
}
|
|
templates = append(templates, t)
|
|
return nil
|
|
})
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &templates, nil
|
|
}
|
|
|
|
func (s *Service) UpdateTemplate(ctx context.Context, t *internal.CustomTemplate) (*internal.CustomTemplate, error) {
|
|
data, err := json.Marshal(t)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = s.db.Update(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte("templates"))
|
|
if b == nil {
|
|
return fmt.Errorf("bucket templates not found")
|
|
}
|
|
return b.Put([]byte(t.Id), data)
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func (s *Service) DeleteTemplate(ctx context.Context, id string) error {
|
|
return s.db.Update(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte("templates"))
|
|
return b.Delete([]byte(id))
|
|
})
|
|
}
|
|
|
|
func (s *Service) GetVersion(ctx context.Context) (string, string, error) {
|
|
//TODO: load from realease properties file, or anything else outside code
|
|
const CURRENT_RPC_VERSION = "3.2.6"
|
|
|
|
result := make(chan string, 1)
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, time.Second*10)
|
|
defer cancel()
|
|
|
|
cmd := exec.CommandContext(ctx, config.Instance().Paths.DownloaderPath, "--version")
|
|
go func() {
|
|
stdout, _ := cmd.Output()
|
|
result <- string(stdout)
|
|
}()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return CURRENT_RPC_VERSION, "", errors.New("requesting yt-dlp version took too long")
|
|
case res := <-result:
|
|
return CURRENT_RPC_VERSION, res, nil
|
|
}
|
|
}
|