diff --git a/frontend/src/Archive.tsx b/frontend/src/Archive.tsx index 4874bf8..b59346a 100644 --- a/frontend/src/Archive.tsx +++ b/frontend/src/Archive.tsx @@ -33,6 +33,7 @@ import { BehaviorSubject, Subject, combineLatestWith, map, share } from 'rxjs' import { useObservable } from './hooks/observable' import { RootState } from './stores/store' import { DeleteRequest, DirectoryEntry } from './types' +import { roundMiB } from './utils' export default function Downloaded() { const settings = useSelector((state: RootState) => state.settings) @@ -52,7 +53,9 @@ export default function Downloaded() { headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({ subdir: '' }) + body: JSON.stringify({ + subdir: '', + }) }) .then(res => res.json()) .then(data => files$.next(data)) @@ -150,7 +153,7 @@ export default function Downloaded() { display: 'flex', flexDirection: 'column', }}> - + {'Archive'} @@ -159,11 +162,20 @@ export default function Downloaded() { addSelected(file.name)} - /> +
+ {!file.isDirectory && + {roundMiB(file.size)} + + } + {!file.isDirectory && addSelected(file.name)} + />} +
} disablePadding > @@ -180,7 +192,10 @@ export default function Downloaded() { : } - +
))} diff --git a/frontend/src/types/index.d.ts b/frontend/src/types/index.d.ts index 15f6221..a2ca267 100644 --- a/frontend/src/types/index.d.ts +++ b/frontend/src/types/index.d.ts @@ -65,16 +65,14 @@ export type DLFormat = { export type DirectoryEntry = { name: string path: string + size: number shaSum: string - isVideo: boolean, + modTime: string + isVideo: boolean isDirectory: boolean } -export type DeleteRequest = Omit< - DirectoryEntry, 'name' | 'isDirectory' | 'isVideo' -> +export type DeleteRequest = Pick -export type PlayRequest = Omit< - DirectoryEntry, 'shaSum' | 'name' | 'isDirectory' | 'isVideo' -> +export type PlayRequest = Pick diff --git a/server/rest/handlers.go b/server/rest/handlers.go index 4eb3a72..d203079 100644 --- a/server/rest/handlers.go +++ b/server/rest/handlers.go @@ -6,7 +6,9 @@ import ( "net/http" "os" "path/filepath" + "sort" "strings" + "time" "github.com/gofiber/fiber/v2" "github.com/marcopeocchi/yt-dlp-web-ui/server/config" @@ -14,11 +16,13 @@ import ( ) type DirectoryEntry struct { - Name string `json:"name"` - Path string `json:"path"` - SHASum string `json:"shaSum"` - IsVideo bool `json:"isVideo"` - IsDirectory bool `json:"isDirectory"` + Name string `json:"name"` + Path string `json:"path"` + Size int64 `json:"size"` + SHASum string `json:"shaSum"` + ModTime time.Time `json:"modTime"` + IsVideo bool `json:"isVideo"` + IsDirectory bool `json:"isDirectory"` } func walkDir(root string) (*[]DirectoryEntry, error) { @@ -36,12 +40,19 @@ func walkDir(root string) (*[]DirectoryEntry, error) { path := filepath.Join(root, d.Name()) + info, err := d.Info() + if err != nil { + return nil, err + } + files = append(files, DirectoryEntry{ Path: path, Name: d.Name(), + Size: info.Size(), SHASum: utils.ShaSumString(path), IsVideo: utils.IsVideo(d), IsDirectory: d.IsDir(), + ModTime: info.ModTime(), }) } @@ -49,7 +60,8 @@ func walkDir(root string) (*[]DirectoryEntry, error) { } type ListRequest struct { - SubDir string `json:"subdir"` + SubDir string `json:"subdir"` + OrderBy string `json:"orderBy"` } func ListDownloaded(ctx *fiber.Ctx) error { @@ -66,6 +78,12 @@ func ListDownloaded(ctx *fiber.Ctx) error { return err } + if req.OrderBy == "modtime" { + sort.SliceStable(*files, func(i, j int) bool { + return (*files)[i].ModTime.After((*files)[j].ModTime) + }) + } + ctx.Status(http.StatusOK) return ctx.JSON(files) } @@ -105,13 +123,18 @@ func SendFile(ctx *fiber.Ctx) error { if err != nil { return err } + decodedStr := string(decoded) root := config.Instance().GetConfig().DownloadPath // TODO: further path / file validations - if strings.Contains(filepath.Dir(string(decoded)), root) { + if strings.Contains(filepath.Dir(decodedStr), root) { + // ctx.Response().Header.Set( + // "Content-Disposition", + // "inline; filename="+filepath.Base(decodedStr), + // ) ctx.SendStatus(fiber.StatusOK) - return ctx.SendFile(string(decoded)) + return ctx.SendFile(decodedStr) } return ctx.SendStatus(fiber.StatusUnauthorized)