97 custom arguments broken (#99)

* golang debug

* handle template in playlist download

* code refactoring, dropped goccy go json
This commit is contained in:
Marco
2023-10-22 15:54:08 +02:00
committed by GitHub
parent 8eb2831bc6
commit ba23485b33
13 changed files with 60 additions and 48 deletions

4
.vscode/launch.json vendored
View File

@@ -5,11 +5,11 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Launch file", "name": "go",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "debug", "mode": "debug",
"program": "${file}" "program": "main.go"
}, },
{ {
"type": "chrome", "type": "chrome",

View File

@@ -7,3 +7,11 @@ export const downloadTemplateState = atom({
({ onSet }) => onSet(e => localStorage.setItem('lastDownloadTemplate', e)) ({ onSet }) => onSet(e => localStorage.setItem('lastDownloadTemplate', e))
] ]
}) })
export const filenameTemplateState = atom({
key: 'filenameTemplateState',
default: localStorage.getItem('lastFilenameTemplate') ?? '',
effects: [
({ onSet }) => onSet(e => localStorage.setItem('lastFilenameTemplate', e))
]
})

View File

@@ -30,7 +30,7 @@ import {
useTransition useTransition
} from 'react' } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { downloadTemplateState } from '../atoms/downloadTemplate' import { downloadTemplateState, filenameTemplateState } from '../atoms/downloadTemplate'
import { settingsState } from '../atoms/settings' import { settingsState } from '../atoms/settings'
import { availableDownloadPathsState, connectedState } from '../atoms/status' import { availableDownloadPathsState, connectedState } from '../atoms/status'
import FormatsGrid from '../components/FormatsGrid' import FormatsGrid from '../components/FormatsGrid'
@@ -74,7 +74,9 @@ export default function DownloadDialog({
const [customArgs, setCustomArgs] = useRecoilState(downloadTemplateState) const [customArgs, setCustomArgs] = useRecoilState(downloadTemplateState)
const [downloadPath, setDownloadPath] = useState(0) const [downloadPath, setDownloadPath] = useState(0)
const [fileNameOverride, setFilenameOverride] = useState('') const [filenameTemplate, setFilenameTemplate] = useRecoilState(
filenameTemplateState
)
const [url, setUrl] = useState('') const [url, setUrl] = useState('')
const [workingUrl, setWorkingUrl] = useState('') const [workingUrl, setWorkingUrl] = useState('')
@@ -110,7 +112,7 @@ export default function DownloadDialog({
immediate || url || workingUrl, immediate || url || workingUrl,
`${cliArgs.toString()} ${toFormatArgs(codes)} ${customArgs}`, `${cliArgs.toString()} ${toFormatArgs(codes)} ${customArgs}`,
availableDownloadPaths[downloadPath] ?? '', availableDownloadPaths[downloadPath] ?? '',
fileNameOverride, filenameTemplate,
isPlaylist, isPlaylist,
) )
@@ -141,27 +143,15 @@ export default function DownloadDialog({
}) })
} }
/**
* Update the url state whenever the input value changes
* @param e Input change event
*/
const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUrl(e.target.value) setUrl(e.target.value)
} }
/** const handleFilenameTemplateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
* Update the filename override state whenever the input value changes setFilenameTemplate(e.target.value)
* @param e Input change event
*/
const handleFilenameOverrideChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFilenameOverride(e.target.value)
localStorage.setItem('last-filename-override', e.target.value) localStorage.setItem('last-filename-override', e.target.value)
} }
/**
* Update the custom args state whenever the input value changes
* @param e Input change event
*/
const handleCustomArgsChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleCustomArgsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setCustomArgs(e.target.value) setCustomArgs(e.target.value)
localStorage.setItem("last-input-args", e.target.value) localStorage.setItem("last-input-args", e.target.value)
@@ -285,8 +275,8 @@ export default function DownloadDialog({
fullWidth fullWidth
label={i18n.t('customFilename')} label={i18n.t('customFilename')}
variant="outlined" variant="outlined"
value={fileNameOverride} value={filenameTemplate}
onChange={handleFilenameOverrideChange} onChange={handleFilenameTemplateChange}
disabled={ disabled={
!isConnected || !isConnected ||
(settings.formatSelection && downloadFormats != null) (settings.formatSelection && downloadFormats != null)

View File

@@ -1,4 +1,4 @@
import { Observable, share } from 'rxjs' import { Observable } from 'rxjs'
import type { DLMetadata, RPCRequest, RPCResponse, RPCResult } from '../types' import type { DLMetadata, RPCRequest, RPCResponse, RPCResult } from '../types'
import { WebSocketSubject, webSocket } from 'rxjs/webSocket' import { WebSocketSubject, webSocket } from 'rxjs/webSocket'
@@ -29,6 +29,12 @@ export class RPCClient {
}) })
} }
private argsSanitizer(args: string) {
return args
.split(' ')
.map(a => a.trim().replaceAll("'", '').replaceAll('"', ''))
}
private async sendHTTP<T>(req: RPCRequest) { private async sendHTTP<T>(req: RPCRequest) {
const res = await fetch(this.httpEndpoint, { const res = await fetch(this.httpEndpoint, {
method: 'POST', method: 'POST',
@@ -57,16 +63,17 @@ export class RPCClient {
method: 'Service.ExecPlaylist', method: 'Service.ExecPlaylist',
params: [{ params: [{
URL: url, URL: url,
Params: args.split(" ").map(a => a.trim()), Params: this.argsSanitizer(args),
Path: pathOverride, Path: pathOverride,
Rename: renameTo,
}] }]
}) })
} }
this.sendHTTP({ this.sendHTTP({
method: 'Service.Exec', method: 'Service.Exec',
params: [{ params: [{
URL: url.split("?list").at(0)!, URL: url.split('?list').at(0)!,
Params: args.split(" ").map(a => a.trim()), Params: this.argsSanitizer(args),
Path: pathOverride, Path: pathOverride,
Rename: renameTo, Rename: renameTo,
}] }]
@@ -78,7 +85,7 @@ export class RPCClient {
return this.sendHTTP<DLMetadata>({ return this.sendHTTP<DLMetadata>({
method: 'Service.Formats', method: 'Service.Formats',
params: [{ params: [{
URL: url.split("?list").at(0)!, URL: url.split('?list').at(0)!,
}] }]
}) })
} }

1
go.mod
View File

@@ -5,7 +5,6 @@ go 1.20
require ( require (
github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/chi/v5 v5.0.10
github.com/go-chi/cors v1.2.1 github.com/go-chi/cors v1.2.1
github.com/goccy/go-json v0.10.2
github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang-jwt/jwt/v5 v5.0.0
github.com/google/uuid v1.3.1 github.com/google/uuid v1.3.1
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0

4
go.sum
View File

@@ -2,8 +2,6 @@ github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
@@ -12,8 +10,6 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa h1:uaAQLGhN4SesB9inOQ1Q6EH+BwTWHQOvwhR0TIJvnYc= github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa h1:uaAQLGhN4SesB9inOQ1Q6EH+BwTWHQOvwhR0TIJvnYc=
github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa/go.mod h1:RvfVo/6Sbnfra9kkvIxDW8NYOOaYsHjF0DdtMCs9cdo= github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa/go.mod h1:RvfVo/6Sbnfra9kkvIxDW8NYOOaYsHjF0DdtMCs9cdo=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@@ -2,6 +2,7 @@ package handlers
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@@ -11,7 +12,6 @@ import (
"time" "time"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/goccy/go-json"
"github.com/marcopeocchi/yt-dlp-web-ui/server/config" "github.com/marcopeocchi/yt-dlp-web-ui/server/config"
"github.com/marcopeocchi/yt-dlp-web-ui/server/utils" "github.com/marcopeocchi/yt-dlp-web-ui/server/utils"
) )

View File

@@ -1,11 +1,11 @@
package handlers package handlers
import ( import (
"encoding/json"
"net/http" "net/http"
"os" "os"
"time" "time"
"github.com/goccy/go-json"
"github.com/golang-jwt/jwt/v5" "github.com/golang-jwt/jwt/v5"
"github.com/marcopeocchi/yt-dlp-web-ui/server/config" "github.com/marcopeocchi/yt-dlp-web-ui/server/config"
"github.com/marcopeocchi/yt-dlp-web-ui/server/utils" "github.com/marcopeocchi/yt-dlp-web-ui/server/utils"

View File

@@ -7,7 +7,7 @@ type DownloadProgress struct {
Status int `json:"process_status"` Status int `json:"process_status"`
Percentage string `json:"percentage"` Percentage string `json:"percentage"`
Speed float32 `json:"speed"` Speed float32 `json:"speed"`
ETA int `json:"eta"` ETA float32 `json:"eta"`
} }
// Used to deser the yt-dlp -J output // Used to deser the yt-dlp -J output
@@ -50,6 +50,8 @@ type ProcessResponse struct {
Id string `json:"id"` Id string `json:"id"`
Progress DownloadProgress `json:"progress"` Progress DownloadProgress `json:"progress"`
Info DownloadInfo `json:"info"` Info DownloadInfo `json:"info"`
Output DownloadOutput `json:"output"`
Params []string `json:"params"`
} }
// struct representing the current status of the memoryDB // struct representing the current status of the memoryDB

View File

@@ -85,6 +85,8 @@ func (m *MemoryDB) All() *[]ProcessResponse {
Id: key.(string), Id: key.(string),
Info: value.(*Process).Info, Info: value.(*Process).Info,
Progress: value.(*Process).Progress, Progress: value.(*Process).Progress,
Output: value.(*Process).Output,
Params: value.(*Process).Params,
}) })
return true return true
}) })
@@ -137,6 +139,8 @@ func (m *MemoryDB) Restore() {
Url: proc.Info.URL, Url: proc.Info.URL,
Info: proc.Info, Info: proc.Info,
Progress: proc.Progress, Progress: proc.Progress,
Output: proc.Output,
Params: proc.Params,
} }
m.table.Store(proc.Id, restored) m.table.Store(proc.Id, restored)

View File

@@ -1,12 +1,12 @@
package internal package internal
import ( import (
"encoding/json"
"errors" "errors"
"log" "log"
"os/exec" "os/exec"
"time" "time"
"github.com/goccy/go-json"
"github.com/marcopeocchi/yt-dlp-web-ui/server/cli" "github.com/marcopeocchi/yt-dlp-web-ui/server/cli"
"github.com/marcopeocchi/yt-dlp-web-ui/server/config" "github.com/marcopeocchi/yt-dlp-web-ui/server/config"
) )
@@ -60,9 +60,11 @@ func PlaylistDetect(req DownloadRequest, mq *MessageQueue, db *MemoryDB) error {
proc := &Process{ proc := &Process{
Url: meta.OriginalURL, Url: meta.OriginalURL,
Progress: DownloadProgress{}, Progress: DownloadProgress{},
Output: DownloadOutput{}, Output: DownloadOutput{
Info: meta, Filename: req.Rename,
Params: req.Params, },
Info: meta,
Params: req.Params,
} }
proc.Info.URL = meta.OriginalURL proc.Info.URL = meta.OriginalURL

View File

@@ -2,13 +2,12 @@ package internal
import ( import (
"bufio" "bufio"
"encoding/json"
"fmt" "fmt"
"regexp" "regexp"
"sync" "sync"
"syscall" "syscall"
"github.com/goccy/go-json"
"log" "log"
"os" "os"
"os/exec" "os/exec"
@@ -38,7 +37,7 @@ type ProgressTemplate struct {
Percentage string `json:"percentage"` Percentage string `json:"percentage"`
Speed float32 `json:"speed"` Speed float32 `json:"speed"`
Size string `json:"size"` Size string `json:"size"`
Eta int `json:"eta"` Eta float32 `json:"eta"`
} }
// Process descriptor // Process descriptor
@@ -70,6 +69,10 @@ func (p *Process) Start() {
return !match return !match
}) })
p.Params = slices.Filter(p.Params, func(e string) bool {
return e != ""
})
out := DownloadOutput{ out := DownloadOutput{
Path: config.Instance().GetConfig().DownloadPath, Path: config.Instance().GetConfig().DownloadPath,
Filename: "%(title)s.%(ext)s", Filename: "%(title)s.%(ext)s",
@@ -87,7 +90,8 @@ func (p *Process) Start() {
"--newline", "--newline",
"--no-colors", "--no-colors",
"--no-playlist", "--no-playlist",
"--progress-template", strings.ReplaceAll(template, "\n", ""), "--progress-template",
strings.NewReplacer("\n", "", "\t", "", " ", "").Replace(template),
"-o", "-o",
fmt.Sprintf("%s/%s", out.Path, out.Filename), fmt.Sprintf("%s/%s", out.Path, out.Filename),
}, p.Params...) }, p.Params...)

View File

@@ -1,9 +1,9 @@
package rest package rest
import ( import (
"encoding/json"
"net/http" "net/http"
"github.com/goccy/go-json"
"github.com/marcopeocchi/yt-dlp-web-ui/server/internal" "github.com/marcopeocchi/yt-dlp-web-ui/server/internal"
) )
@@ -19,7 +19,7 @@ func (h *Handler) Exec() http.HandlerFunc {
req := internal.DownloadRequest{} req := internal.DownloadRequest{}
if err := json.NewDecoder(r.Body).DecodeContext(r.Context(), &req); err != nil { if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} }
@@ -29,7 +29,7 @@ func (h *Handler) Exec() http.HandlerFunc {
return return
} }
err = json.NewEncoder(w).EncodeContext(r.Context(), id) err = json.NewEncoder(w).Encode(id)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} }
@@ -48,7 +48,7 @@ func (h *Handler) Running() http.HandlerFunc {
return return
} }
err = json.NewEncoder(w).EncodeContext(r.Context(), res) err = json.NewEncoder(w).Encode(res)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} }
@@ -63,7 +63,7 @@ func (h *Handler) SetCookies() http.HandlerFunc {
req := new(internal.SetCookiesRequest) req := new(internal.SetCookiesRequest)
err := json.NewDecoder(r.Body).DecodeContext(r.Context(), req) err := json.NewDecoder(r.Body).Decode(req)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
@@ -75,7 +75,7 @@ func (h *Handler) SetCookies() http.HandlerFunc {
return return
} }
err = json.NewEncoder(w).EncodeContext(r.Context(), "ok") err = json.NewEncoder(w).Encode("ok")
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} }