added status API endpoint
This commit is contained in:
@@ -23,6 +23,6 @@ type Format struct {
|
||||
Resolution string `json:"resolution"`
|
||||
VCodec string `json:"vcodec"`
|
||||
ACodec string `json:"acodec"`
|
||||
Size float32 `json:"filesize_approx"`
|
||||
Size float64 `json:"filesize_approx"`
|
||||
Language string `json:"language"`
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import "time"
|
||||
// Used to unmarshall yt-dlp progress
|
||||
type ProgressTemplate struct {
|
||||
Percentage string `json:"percentage"`
|
||||
Speed float32 `json:"speed"`
|
||||
Speed float64 `json:"speed"`
|
||||
Size string `json:"size"`
|
||||
Eta float32 `json:"eta"`
|
||||
Eta float64 `json:"eta"`
|
||||
}
|
||||
|
||||
type PostprocessTemplate struct {
|
||||
@@ -25,8 +25,8 @@ type DownloadOutput struct {
|
||||
type DownloadProgress struct {
|
||||
Status int `json:"process_status"`
|
||||
Percentage string `json:"percentage"`
|
||||
Speed float32 `json:"speed"`
|
||||
ETA float32 `json:"eta"`
|
||||
Speed float64 `json:"speed"`
|
||||
ETA float64 `json:"eta"`
|
||||
}
|
||||
|
||||
// Used to deser the yt-dlp -J output
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/openid"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/rest"
|
||||
ytdlpRPC "github.com/marcopeocchi/yt-dlp-web-ui/v3/server/rpc"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/status"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
@@ -221,6 +222,9 @@ func newServer(c serverConfig) *http.Server {
|
||||
// Logging
|
||||
r.Route("/log", logging.ApplyRouter(observableLogger))
|
||||
|
||||
// Status
|
||||
r.Route("/status", status.ApplyRouter(c.mdb))
|
||||
|
||||
return &http.Server{Handler: r}
|
||||
}
|
||||
|
||||
|
||||
28
server/status/domain/status.go
Normal file
28
server/status/domain/status.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
Downloading int `json:"downloading"`
|
||||
Pending int `json:"pending"`
|
||||
Completed int `json:"completed"`
|
||||
DownloadSpeed int `json:"download_speed"`
|
||||
}
|
||||
|
||||
type Repository interface {
|
||||
Pending(ctx context.Context) int
|
||||
Completed(ctx context.Context) int
|
||||
Downloading(ctx context.Context) int
|
||||
DownloadSpeed(ctx context.Context) int64
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
Status(ctx context.Context) (*Status, error)
|
||||
}
|
||||
|
||||
type RestHandler interface {
|
||||
Status() http.HandlerFunc
|
||||
}
|
||||
65
server/status/repository/repository.go
Normal file
65
server/status/repository/repository.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/internal"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/status/domain"
|
||||
)
|
||||
|
||||
type Repository struct {
|
||||
mdb *internal.MemoryDB
|
||||
}
|
||||
|
||||
// DownloadSpeed implements domain.Repository.
|
||||
func (r *Repository) DownloadSpeed(ctx context.Context) int64 {
|
||||
processes := r.mdb.All()
|
||||
|
||||
var downloadSpeed float64
|
||||
|
||||
for _, p := range *processes {
|
||||
downloadSpeed += p.Progress.Speed
|
||||
}
|
||||
|
||||
return int64(downloadSpeed)
|
||||
}
|
||||
|
||||
// Completed implements domain.Repository.
|
||||
func (r *Repository) Completed(ctx context.Context) int {
|
||||
processes := r.mdb.All()
|
||||
|
||||
completed := slices.DeleteFunc(*processes, func(p internal.ProcessResponse) bool {
|
||||
return p.Progress.Status != internal.StatusCompleted
|
||||
})
|
||||
|
||||
return len(completed)
|
||||
}
|
||||
|
||||
// Downloading implements domain.Repository.
|
||||
func (r *Repository) Downloading(ctx context.Context) int {
|
||||
processes := r.mdb.All()
|
||||
|
||||
downloading := slices.DeleteFunc(*processes, func(p internal.ProcessResponse) bool {
|
||||
return p.Progress.Status != internal.StatusDownloading
|
||||
})
|
||||
|
||||
return len(downloading)
|
||||
}
|
||||
|
||||
// Pending implements domain.Repository.
|
||||
func (r *Repository) Pending(ctx context.Context) int {
|
||||
processes := r.mdb.All()
|
||||
|
||||
pending := slices.DeleteFunc(*processes, func(p internal.ProcessResponse) bool {
|
||||
return p.Progress.Status != internal.StatusPending
|
||||
})
|
||||
|
||||
return len(pending)
|
||||
}
|
||||
|
||||
func New(mdb *internal.MemoryDB) domain.Repository {
|
||||
return &Repository{
|
||||
mdb: mdb,
|
||||
}
|
||||
}
|
||||
38
server/status/rest/handler.go
Normal file
38
server/status/rest/handler.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/status/domain"
|
||||
)
|
||||
|
||||
type RestHandler struct {
|
||||
service domain.Service
|
||||
}
|
||||
|
||||
// Status implements domain.RestHandler.
|
||||
func (h *RestHandler) Status() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
status, err := h.service.Status(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(status); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func New(service domain.Service) domain.RestHandler {
|
||||
return &RestHandler{
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
69
server/status/service/service.go
Normal file
69
server/status/service/service.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/rest"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/status/domain"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
repository domain.Repository
|
||||
utilityService *rest.Service
|
||||
}
|
||||
|
||||
// Version implements domain.Status.
|
||||
func (s *Service) Status(ctx context.Context) (*domain.Status, error) {
|
||||
// rpcVersion, downloaderVersion, err := s.utilityService.GetVersion(ctx)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
pending int
|
||||
downloading int
|
||||
completed int
|
||||
speed int64
|
||||
// version = fmt.Sprintf("RPC: %s yt-dlp: %s", rpcVersion, downloaderVersion)
|
||||
)
|
||||
|
||||
wg.Add(4)
|
||||
|
||||
go func() {
|
||||
pending = s.repository.Pending(ctx)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
downloading = s.repository.Downloading(ctx)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
completed = s.repository.Completed(ctx)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
speed = s.repository.DownloadSpeed(ctx)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return &domain.Status{
|
||||
Downloading: downloading,
|
||||
Pending: pending,
|
||||
Completed: completed,
|
||||
DownloadSpeed: int(speed),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func New(repository domain.Repository, utilityService *rest.Service) domain.Service {
|
||||
return &Service{
|
||||
repository: repository,
|
||||
utilityService: utilityService,
|
||||
}
|
||||
}
|
||||
21
server/status/status.go
Normal file
21
server/status/status.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/internal"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/status/repository"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/status/rest"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/v3/server/status/service"
|
||||
)
|
||||
|
||||
func ApplyRouter(mdb *internal.MemoryDB) func(chi.Router) {
|
||||
var (
|
||||
r = repository.New(mdb)
|
||||
s = service.New(r, nil) //TODO: nil, wtf?
|
||||
h = rest.New(s)
|
||||
)
|
||||
|
||||
return func(r chi.Router) {
|
||||
r.Get("/", h.Status())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user