Compare commits

..

11 Commits

Author SHA1 Message Date
Marco Piovanello
f7539d8abf prevent RCEs with crafted video files urls 2025-07-23 10:16:40 +02:00
Marco Piovanello
8a73079fad Update Dockerfile 2025-04-13 20:13:59 +02:00
f578f44cfd refactor: prevent multiple slashes 2025-03-30 10:29:13 +02:00
cbe16c5c6c refactoring: readded abort controller to httpClient.ts 2025-03-30 10:21:19 +02:00
3cebaf7f61 refactor: extra slashes prevention 2025-03-30 10:17:30 +02:00
Marco Piovanello
2d2cb1dc3a Update README.md 2025-03-30 09:54:27 +02:00
Marco Piovanello
43bcc40907 293 tiny gui improvement (#296)
* clicking on the speed dial will open download dialog

* refactor: prevent multiple slashes
2025-03-29 21:27:28 +01:00
Marco Piovanello
2af27e51be Chore dockerfile refactor (#287)
* removed yt-dlp alpine package

* use python3-alpine base image
2025-03-22 16:17:25 +01:00
Marco Piovanello
8c18242aaf removed yt-dlp alpine package (#286) 2025-03-22 15:27:48 +01:00
Marco Piovanello
66bebb2529 Update README.md 2025-03-17 11:23:29 +01:00
Marco Piovanello
e223e030ac restrict user with a whitelist (#282) 2025-03-17 11:13:20 +01:00
6 changed files with 38 additions and 14 deletions

View File

@@ -24,11 +24,12 @@ COPY --from=ui /usr/src/yt-dlp-webui/frontend /usr/src/yt-dlp-webui/frontend
RUN CGO_ENABLED=0 GOOS=linux go build -o yt-dlp-webui RUN CGO_ENABLED=0 GOOS=linux go build -o yt-dlp-webui
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# dependencies ---------------------------------------------------------------- # Runtime ---------------------------------------------------------------------
FROM alpine:edge FROM python:3.13.2-alpine3.21
RUN apk update && \ RUN apk update && \
apk add ffmpeg yt-dlp ca-certificates curl wget psmisc apk add ffmpeg ca-certificates curl wget gnutls --no-cache && \
pip install "yt-dlp[default,curl-cffi,mutagen,pycryptodomex,phantomjs,secretstorage]"
VOLUME /downloads /config VOLUME /downloads /config

View File

@@ -28,7 +28,7 @@ docker pull ghcr.io/marcopiovanello/yt-dlp-web-ui:latest
## Community stuff ## Community stuff
Feel free to join :) Feel free to join :)
[![Discord Banner](https://api.weblutions.com/discord/invite/3Sj9ZZHv/)](https://discord.gg/WRnVWr4y) [Discord](https://discord.gg/GZAX5FfGzE)
## Some screeshots ## Some screeshots
![image](https://github.com/user-attachments/assets/fc43a3fb-ecf9-449d-b5cb-5d5635020c00) ![image](https://github.com/user-attachments/assets/fc43a3fb-ecf9-449d-b5cb-5d5635020c00)

View File

@@ -121,14 +121,18 @@ export const appTitleState = atomWithStorage(
export const serverAddressAndPortState = atom((get) => { export const serverAddressAndPortState = atom((get) => {
if (get(servedFromReverseProxySubDirState)) { if (get(servedFromReverseProxySubDirState)) {
return `${get(serverAddressState)}/${get(servedFromReverseProxySubDirState)}/` return `${get(serverAddressState)}/${get(servedFromReverseProxySubDirState)}/`
.replaceAll('"', '') // TODO: atomWithStorage put extra double quotes on strings .replaceAll('"', '') // XXX: atomWithStorage uses JSON.stringify to serialize
.replaceAll('//', '/') // which puts extra double quotes.
} }
if (get(servedFromReverseProxyState)) { if (get(servedFromReverseProxyState)) {
return `${get(serverAddressState)}` return `${get(serverAddressState)}`
.replaceAll('"', '') .replaceAll('"', '')
} }
return `${get(serverAddressState)}:${get(serverPortState)}`
const sap = `${get(serverAddressState)}:${get(serverPortState)}`
.replaceAll('"', '') .replaceAll('"', '')
return sap.endsWith('/') ? sap.slice(0, -1) : sap
}) })
export const serverURL = atom((get) => export const serverURL = atom((get) =>
@@ -137,12 +141,16 @@ export const serverURL = atom((get) =>
export const rpcWebSocketEndpoint = atom((get) => { export const rpcWebSocketEndpoint = atom((get) => {
const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:' const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
return `${proto}//${get(serverAddressAndPortState)}/rpc/ws` const sap = get(serverAddressAndPortState)
return `${proto}//${sap.endsWith('/') ? sap.slice(0, -1) : sap}/rpc/ws`
}) })
export const rpcHTTPEndpoint = atom((get) => { export const rpcHTTPEndpoint = atom((get) => {
const proto = window.location.protocol const proto = window.location.protocol
return `${proto}//${get(serverAddressAndPortState)}/rpc/http` const sap = get(serverAddressAndPortState)
return `${proto}//${sap.endsWith('/') ? sap.slice(0, -1) : sap}/rpc/http`
}) })
export const serverSideCookiesState = atom<Promise<string>>(async (get) => await pipe( export const serverSideCookiesState = atom<Promise<string>>(async (get) => await pipe(

View File

@@ -32,6 +32,7 @@ const HomeSpeedDial: React.FC<Props> = ({ onDownloadOpen, onEditorOpen }) => {
ariaLabel="Home speed dial" ariaLabel="Home speed dial"
sx={{ position: 'absolute', bottom: 64, right: 24 }} sx={{ position: 'absolute', bottom: 64, right: 24 }}
icon={<SpeedDialIcon />} icon={<SpeedDialIcon />}
onClick={onDownloadOpen}
> >
<SpeedDialAction <SpeedDialAction
icon={listView ? <ViewAgendaIcon /> : <FormatListBulleted />} icon={listView ? <ViewAgendaIcon /> : <FormatListBulleted />}

View File

@@ -1,6 +1,9 @@
import { tryCatch } from 'fp-ts/TaskEither' import { tryCatch } from 'fp-ts/TaskEither'
import * as J from 'fp-ts/Json'
import * as E from 'fp-ts/Either'
import { pipe } from 'fp-ts/lib/function'
async function fetcher<T>(url: string, opt?: RequestInit): Promise<T> { async function fetcher(url: string, opt?: RequestInit, controller?: AbortController): Promise<string> {
const jwt = localStorage.getItem('token') const jwt = localStorage.getItem('token')
if (opt && !opt.headers) { if (opt && !opt.headers) {
@@ -14,17 +17,27 @@ async function fetcher<T>(url: string, opt?: RequestInit): Promise<T> {
headers: { headers: {
...opt?.headers, ...opt?.headers,
'X-Authentication': jwt ?? '' 'X-Authentication': jwt ?? ''
} },
signal: controller?.signal
}) })
if (!res.ok) { if (!res.ok) {
throw await res.text() throw await res.text()
} }
return res.json() as T
return res.text()
} }
export const ffetch = <T>(url: string, opt?: RequestInit) => tryCatch( export const ffetch = <T>(url: string, opt?: RequestInit, controller?: AbortController) => tryCatch(
() => fetcher<T>(url, opt), async () => pipe(
await fetcher(url, opt, controller),
J.parse,
E.match(
(l) => l as T,
(r) => r as T
)
),
(e) => `error while fetching: ${e}` (e) => `error while fetching: ${e}`
) )

View File

@@ -93,6 +93,7 @@ func (p *Process) Start() {
baseParams := []string{ baseParams := []string{
strings.Split(p.Url, "?list")[0], //no playlist strings.Split(p.Url, "?list")[0], //no playlist
"--no-exec",
"--newline", "--newline",
"--no-colors", "--no-colors",
"--no-playlist", "--no-playlist",