code refactoring, added router, moved download api path

This commit is contained in:
2024-02-23 10:55:33 +01:00
parent 65b0c8bc0e
commit 1cfda047cb
20 changed files with 146 additions and 41 deletions

3
.gitignore vendored
View File

@@ -13,4 +13,5 @@ yt-dlp-webui
session.dat
config.yml
cookies.txt
__debug*
__debug*
app/

View File

@@ -30,6 +30,8 @@ func ApplyRouter(db *sql.DB, mdb *internal.MemoryDB, mq *internal.MessageQueue)
r.Post("/template", h.AddTemplate())
r.Get("/template/all", h.GetTemplates())
r.Delete("/template/{id}", h.DeleteTemplate())
r.Get("/tree", h.DirectoryTree())
r.Get("/d/{id}", h.DownloadFile())
}
}

View File

@@ -2,7 +2,10 @@ package rest
import (
"encoding/json"
"io"
"net/http"
"os"
"path/filepath"
"github.com/go-chi/chi/v5"
"github.com/marcopeocchi/yt-dlp-web-ui/server/internal"
@@ -173,3 +176,36 @@ func (h *Handler) DirectoryTree() http.HandlerFunc {
}
}
}
func (h *Handler) DownloadFile() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
w.Header().Set("Content-Type", "application/json")
id := chi.URLParam(r, "id")
path, err := h.service.DownloadFile(r.Context(), id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Add(
"Content-Disposition",
"inline; filename="+filepath.Base(*path),
)
w.Header().Set(
"Content-Type",
"application/octet-stream",
)
fd, err := os.Open(*path)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
io.Copy(w, fd)
}
}

View File

@@ -123,3 +123,12 @@ func (s *Service) DeleteTemplate(ctx context.Context, id string) error {
func (s *Service) DirectoryTree(ctx context.Context) (*internal.Stack[sys.FSNode], error) {
return sys.DirectoryTree()
}
func (s *Service) DownloadFile(ctx context.Context, id string) (*string, error) {
p, err := s.mdb.Get(id)
if err != nil {
return nil, err
}
return &p.Output.Path, nil
}

View File

@@ -25,6 +25,7 @@
"dependencies": {
"@fontsource/roboto": "^5.0.8",
"fp-ts": "^2.16.2",
"lucide-svelte": "^0.323.0"
"lucide-svelte": "^0.323.0",
"svelte-spa-router": "^4.0.1"
}
}

14
ui/pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ dependencies:
lucide-svelte:
specifier: ^0.323.0
version: 0.323.0(svelte@4.2.10)
svelte-spa-router:
specifier: ^4.0.1
version: 4.0.1
devDependencies:
'@sveltejs/vite-plugin-svelte':
@@ -1254,6 +1257,11 @@ packages:
picomatch: 2.3.1
dev: true
/regexparam@2.0.2:
resolution: {integrity: sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w==}
engines: {node: '>=8'}
dev: false
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -1498,6 +1506,12 @@ packages:
typescript: 5.3.3
dev: true
/svelte-spa-router@4.0.1:
resolution: {integrity: sha512-2JkmUQ2f9jRluijL58LtdQBIpynSbem2eBGp4zXdi7aDY1znbR6yjw0KsonD0aq2QLwf4Yx4tBJQjxIjgjXHKg==}
dependencies:
regexparam: 2.0.2
dev: false
/svelte@4.2.10:
resolution: {integrity: sha512-Ep06yCaCdgG1Mafb/Rx8sJ1QS3RW2I2BxGp2Ui9LBHSZ2/tO/aGLc5WqPjgiAP6KAnLJGaIr/zzwQlOo1b8MxA==}
engines: {node: '>=16'}

View File

@@ -1,15 +1,24 @@
<script lang="ts">
import { SvelteToast } from '@zerodevx/svelte-toast';
import Router from 'svelte-spa-router';
import { wrap } from 'svelte-spa-router/wrap';
import Footer from './lib/Footer.svelte';
import Home from './lib/Home.svelte';
import Home from './views/Home.svelte';
import Navbar from './lib/Navbar.svelte';
const routes = {
'/': Home,
'/settings': wrap({
asyncComponent: () => import('./views/SettingsView.svelte'),
}),
};
</script>
<main
class="bg-neutral-50 dark:bg-neutral-900 h-screen text-neutral-950 dark:text-neutral-50"
>
<Navbar />
<Home />
<Router {routes} />
<Footer />
<SvelteToast />
<!-- <FloatingAction /> -->

View File

@@ -5,7 +5,7 @@
</script>
<button
class={`px-2.5 py-2 rounded-lg bg-orange-300 hover:bg-orange-400 hover:duration-150 text-sm font-semibold ${
class={`px-2.5 py-2 rounded-lg bg-blue-300 hover:bg-blue-400 hover:duration-150 text-sm font-semibold ${
disabled && 'bg-neutral-300 hover:bg-neutral-300'
} ${clazz}`}
{disabled}

View File

@@ -3,7 +3,7 @@
</script>
<div
class="flex items-center gap-1.5 p-1 bg-orange-200 rounded-lg text-neutral-900"
class="flex items-center gap-1.5 p-1 bg-blue-200 rounded-lg text-neutral-900"
>
<slot />
{text}

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import { get } from 'svelte/store';
import Chip from './Chip.svelte';
import type { RPCResult } from './types';
import { formatSpeedMiB, mapProcessStatus, roundMiB } from './utils';
import { rpcClient } from './store';
import Button from './Button.svelte';
import Chip from './Chip.svelte';
import { rpcClient, serverApiEndpoint } from './store';
import type { RPCResult } from './types';
import { formatSpeedMiB, roundMiB } from './utils';
export let download: RPCResult;
@@ -14,12 +14,12 @@
<div
class="flex gap-4
bg-neutral-100 dark:bg-neutral-800
pt-2 md:p-4
p-2 md:p-4
rounded-lg shadow-lg
border dark:border-neutral-700"
>
<div
class="h-full w-96 bg-cover bg-center rounded"
class="h-full hidden sm:block w-96 bg-cover bg-center rounded"
style="background-image: url({download.info.thumbnail})"
/>
@@ -34,7 +34,7 @@
</div>
<div class="flex flex-col justify-end gap-2 select-none flex-wrap">
<div class="flex items-center gap-2 text-sm">
<div class="hidden sm:flex items-center gap-2 text-sm">
{#if download.info.vcodec}
<Chip text={download.info.vcodec} />
{/if}
@@ -50,9 +50,9 @@
{#if download.info.filesize_approx}
<Chip text={roundMiB(download.info.filesize_approx)} />
{/if}
{#if download.progress.process_status}
<!-- {#if download.progress.process_status}
<Chip text={mapProcessStatus(download.progress.process_status)} />
{/if}
{/if} -->
{#if download.progress.speed}
<Chip text={formatSpeedMiB(download.progress.speed)} />
{/if}
@@ -62,6 +62,7 @@
<Button class="w-14" on:click={() => remove(download.id)}>Stop</Button>
{#if download.progress.process_status === 2}
<Button class="w-18">Download</Button>
<!-- <a href={`${$serverApiEndpoint}/api/v1/d/${download.id}`}>d</a> -->
{/if}
</div>
@@ -72,7 +73,7 @@
class={`h-2 rounded-full ${
download.progress.process_status === 2
? 'bg-green-600'
: 'bg-orange-500'
: 'bg-blue-500'
}`}
style="width: {download.progress.percentage}"
/>

View File

@@ -5,18 +5,18 @@
<div class="absolute bottom-10 right-10">
<!-- <div class="relative mb-4 flex flex-col justify-center items-center gap-2">
<button
class="relative flex items-center justify-center bg-orange-500 h-8 w-8 z-10 rounded-2xl shadow-xl text-neutral-100"
class="relative flex items-center justify-center bg-blue-500 h-8 w-8 z-10 rounded-2xl shadow-xl text-neutral-100"
>
<Plus size={18} />
</button>
<button
class="relative flex items-center justify-center bg-orange-500 h-8 w-8 z-10 rounded-2xl shadow-xl text-neutral-100"
class="relative flex items-center justify-center bg-blue-500 h-8 w-8 z-10 rounded-2xl shadow-xl text-neutral-100"
>
<Plus size={18} />
</button>
</div> -->
<button
class="relative bg-orange-500 p-5 z-10 rounded-2xl shadow-xl text-neutral-100"
class="relative bg-blue-500 p-5 z-10 rounded-2xl shadow-xl text-neutral-100"
>
<Plus />
</button>

View File

@@ -1,8 +1,7 @@
<script lang="ts">
import { ChevronUp, ChevronDown } from 'lucide-svelte';
import { ChevronDown, ChevronUp } from 'lucide-svelte';
import { cubicOut } from 'svelte/easing';
import { tweened } from 'svelte/motion';
import Settings from './Settings.svelte';
import NewDownload from './NewDownload.svelte';
const height = tweened(52, {
@@ -11,7 +10,7 @@
});
const minHeight = 52;
const maxHeight = window.innerHeight - 60;
const maxHeight = window.innerHeight / 1.5;
let open = false;
$: open = $height > minHeight;
@@ -19,7 +18,7 @@
<footer
class="
absolute bottom-0
fixed bottom-0 z-10
w-full
p-2
bg-neutral-100 dark:bg-neutral-800
@@ -44,7 +43,6 @@
{#if $height > 100}
<div class="mt-2">
<NewDownload />
<Settings />
</div>
{/if}
</footer>

View File

@@ -24,16 +24,16 @@
for="formats"
class="
[&_p]:text-gray-900 [&_span]:text-gray-500
peer-checked:[&_p]:text-white peer-checked:[&_span]:text-orange-100
peer-checked:[&_p]:text-white peer-checked:[&_span]:text-blue-100
peer-focus:ring-2 peer-focus:ring-white
peer-focus:ring-opacity-60 peer-focus:ring-offset-2 peer-focus:ring-offset-orange-300
peer-focus:ring-opacity-60 peer-focus:ring-offset-2 peer-focus:ring-offset-blue-300
bg-white
relative flex
cursor-pointer
rounded-lg px-5 py-4
shadow-md
focus:outline-none
peer-checked:bg-orange-700/75
peer-checked:bg-blue-700/75
peer-checked:text-white"
>
<div class="flex w-full items-center justify-between">

View File

@@ -1,10 +1,17 @@
<script lang="ts">
import { ArrowDownUp, Github, HardDrive, Network } from 'lucide-svelte';
import {
ArrowDownUp,
Github,
HardDrive,
Network,
Settings,
} from 'lucide-svelte';
import { downloads, rpcClient, serverApiEndpoint } from './store';
import { formatGiB, formatSpeedMiB } from './utils';
import * as O from 'fp-ts/Option';
import { pipe } from 'fp-ts/lib/function';
import { onDestroy } from 'svelte';
import { link } from 'svelte-spa-router';
let downloadSpeed = 0;
@@ -34,13 +41,13 @@
shadow-lg
select-none"
>
<div class="font-semibold text-lg">yt-dlp WebUI</div>
<a use:link={'/'} href="/" class="font-semibold text-lg">yt-dlp WebUI</a>
<div />
<div class="flex items-center gap-2 text-sm">
<div
class="flex items-center gap-1.5 p-1 text-neutral-900 bg-orange-200 rounded-lg"
class="hidden sm:flex items-center gap-1.5 p-1 text-neutral-900 bg-blue-200 rounded-lg"
>
<ArrowDownUp size={18} />
<div>
@@ -50,7 +57,7 @@
<div class="flex items-center gap-2 text-sm">
<div
class="flex items-center gap-1.5 p-1 text-neutral-900 bg-orange-200 rounded-lg"
class="flex items-center gap-1.5 p-1 text-neutral-900 bg-blue-200 rounded-lg"
>
<HardDrive size={18} />
<div>
@@ -63,7 +70,7 @@
</div>
<div
class="flex items-center gap-1.5 p-1 text-neutral-900 bg-orange-200 rounded-lg"
class="flex items-center gap-1.5 p-1 text-neutral-900 bg-blue-200 rounded-lg"
>
<Network size={18} />
<div>
@@ -73,10 +80,18 @@
<a
href="https://github.com/marcopeocchi/yt-dlp-web-ui"
class="flex items-center gap-1.5 p-1 text-neutral-900 bg-orange-200 rounded-lg"
class="flex items-center gap-1.5 p-1 text-neutral-900 bg-blue-200 rounded-lg"
>
<Github size={18} />
</a>
<a
use:link={'/settings'}
href="/settings"
class="flex items-center gap-1.5 p-1 text-neutral-900 bg-blue-200 rounded-lg"
>
<Settings size={18} />
</a>
</div>
</div>
</nav>

View File

@@ -13,7 +13,7 @@
border rounded-lg
appearance-none
text-sm font-semibold
focus:outline-orange-300
focus:outline-blue-300
"
bind:value
{disabled}

View File

@@ -10,7 +10,7 @@
const update = () => (loading = get(rpcClient).updateExecutable());
</script>
<div class="w-full px-8 mt-8">
<div class="w-full">
<div class="font-semibold text-lg mb-4">Settings</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">

View File

@@ -1,7 +1,7 @@
<div role="status">
<svg
aria-hidden="true"
class="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-orange-400"
class="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-blue-400"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"

View File

@@ -12,7 +12,13 @@
<label for=""> {label} </label>
<input
type="text"
class={`p-2 bg-neutral-50 border rounded-lg focus:outline-orange-300 ${clazz}`}
class={`p-2
bg-neutral-50 border
rounded-lg
focus:outline-blue-300
dark:bg-neutral-700 dark:border-neutral-900
${clazz}
`}
on:keyup
bind:value
{placeholder}

View File

@@ -2,10 +2,10 @@
import * as O from 'fp-ts/Option';
import { pipe } from 'fp-ts/lib/function';
import { onDestroy } from 'svelte';
import DownloadCard from './DownloadCard.svelte';
import Spinner from './Spinner.svelte';
import { downloads, rpcClient } from './store';
import { datetimeCompareFunc, isRPCResponse } from './utils';
import DownloadCard from '../lib/DownloadCard.svelte';
import Spinner from '../lib/Spinner.svelte';
import { downloads, rpcClient } from '../lib/store';
import { datetimeCompareFunc, isRPCResponse } from '../lib/utils';
const unsubscribe = rpcClient.subscribe(($client) => {
setInterval(() => $client.running(), 750);

View File

@@ -0,0 +1,13 @@
<script lang="ts">
import Settings from '../lib/Settings.svelte';
</script>
<main
class="bg-neutral-100 dark:bg-neutral-800
rounded-xl
border dark:border-neutral-700
shadow-lg
m-8 p-4"
>
<Settings />
</main>