Compare commits
No commits in common. "main" and "v1.1.4" have entirely different histories.
|
@ -3,7 +3,7 @@ testdata_dir = "testdata"
|
||||||
tmp_dir = "tmp"
|
tmp_dir = "tmp"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
args_bin = ["-l", "0.0.0.0", "-p", "3000"]
|
args_bin = ["-l", "0.0.0.0"]
|
||||||
bin = "./out/ytdl-web"
|
bin = "./out/ytdl-web"
|
||||||
cmd = "build"
|
cmd = "build"
|
||||||
delay = 1000
|
delay = 1000
|
||||||
|
|
12
.envrc
12
.envrc
|
@ -1,11 +1,3 @@
|
||||||
if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then
|
source_url "https://raw.githubusercontent.com/cachix/devenv/d1f7b48e35e6dee421cfd0f51481d17f77586997/direnvrc" "sha256-YBzqskFZxmNb3kYVoKD9ZixoPXJh1C9ZvTLGFRkauZ0="
|
||||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs="
|
|
||||||
fi
|
|
||||||
|
|
||||||
nix_direnv_watch_file nix/devenv.nix
|
use devenv
|
||||||
nix_direnv_watch_file devenv.lock
|
|
||||||
nix_direnv_watch_file devenv.yaml
|
|
||||||
if ! use flake . --impure
|
|
||||||
then
|
|
||||||
echo "devenv could not be built. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2
|
|
||||||
fi
|
|
|
@ -1,4 +1,4 @@
|
||||||
ARG GOLANG_VERSION="1.22.1"
|
ARG GOLANG_VERSION="1.20.11"
|
||||||
ARG DEBIAN_VERSION="bookworm"
|
ARG DEBIAN_VERSION="bookworm"
|
||||||
|
|
||||||
FROM golang:${GOLANG_VERSION}-${DEBIAN_VERSION} AS build
|
FROM golang:${GOLANG_VERSION}-${DEBIAN_VERSION} AS build
|
||||||
|
@ -27,7 +27,7 @@ RUN go build \
|
||||||
|
|
||||||
FROM python:${DEBIAN_VERSION}
|
FROM python:${DEBIAN_VERSION}
|
||||||
|
|
||||||
ARG YTDLP_VERSION="2024.11.04"
|
ARG YTDLP_VERSION="2023.12.30"
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ You can configure the application using environment variables
|
||||||
| ---------------------------------- | ----------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------ |
|
| ---------------------------------- | ----------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------ |
|
||||||
| YTDL_CONFIGDIR | Add a custom config directory to search for the config file | ` ` | |
|
| YTDL_CONFIGDIR | Add a custom config directory to search for the config file | ` ` | |
|
||||||
| YTDL_ENV | The application environment | `Production` | `Development`, `Staging`, `Production` |
|
| YTDL_ENV | The application environment | `Production` | `Development`, `Staging`, `Production` |
|
||||||
| YTDL_YTDLP_BINARYPATH | The path to the yt-dlp binary | `yt-dlp` | |
|
| YTDL_BINARYPATH | The path to the yt-dlp binary | `yt-dlp` | |
|
||||||
| YTDL_HTTP_PORT | The tcp port for the web server to listen on | `8080` | |
|
| YTDL_HTTP_PORT | The tcp port for the web server to listen on | `8080` | |
|
||||||
| YTDL_HTTP_LISTEN | The address for the web server to listen on | `127.0.0.1` | `0.0.0.0`, `127.0.0.1`, etc. |
|
| YTDL_HTTP_LISTEN | The address for the web server to listen on | `127.0.0.1` | `0.0.0.0`, `127.0.0.1`, etc. |
|
||||||
| YTDL_HTTP_BASEPATH | The base path of the application, useful for reverse proxies | `/` | |
|
| YTDL_HTTP_BASEPATH | The base path of the application, useful for reverse proxies | `/` | |
|
||||||
|
@ -36,7 +36,7 @@ You can configure the application using environment variables
|
||||||
| YTDL_COOKIES_FROMBROWSER_BROWSER | The name of the browser to load cookies from. (if specified, it disables YTDL_COOKIES_FILEPATH) | ` ` | `brave`, `chrome`, `chromium`, `edge`, `firefox`, `opera`, `safari`, `vivaldi` |
|
| YTDL_COOKIES_FROMBROWSER_BROWSER | The name of the browser to load cookies from. (if specified, it disables YTDL_COOKIES_FILEPATH) | ` ` | `brave`, `chrome`, `chromium`, `edge`, `firefox`, `opera`, `safari`, `vivaldi` |
|
||||||
| YTDL_COOKIES_FROMBROWSER_KEYRING | The name of the keyring for decrypting cookies for the chromium browser on linux | ` ` | `basictext`, `gnomekeyring`, `kwallet` |
|
| YTDL_COOKIES_FROMBROWSER_KEYRING | The name of the keyring for decrypting cookies for the chromium browser on linux | ` ` | `basictext`, `gnomekeyring`, `kwallet` |
|
||||||
| YTDL_COOKIES_FROMBROWSER_PROFILE | The browser profile to load cookies from | ` ` | |
|
| YTDL_COOKIES_FROMBROWSER_PROFILE | The browser profile to load cookies from | ` ` | |
|
||||||
| YTDL_COOKIES_FROMBROWSER_CONTAINER | The container name (if firefox) to load the cookies from | ` ` | |
|
| YTDL_COOKIES_FROMBROWSER_CONTAINER | The container name (if firefox) top load the cookies from | ` ` | |
|
||||||
|
|
||||||
## Building from source
|
## Building from source
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@ package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/samber/lo"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.fifitido.net/ytdl-web/app"
|
"go.fifitido.net/ytdl-web/app"
|
||||||
"go.fifitido.net/ytdl-web/app/models"
|
"go.fifitido.net/ytdl-web/app/models"
|
||||||
|
@ -108,10 +108,6 @@ func (c *DownloadController) ListDownloadLinks(w http.ResponseWriter, r *http.Re
|
||||||
}, layout...)
|
}, layout...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
BUF_LEN = 1024
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *DownloadController) ProxyDownload(w http.ResponseWriter, r *http.Request) {
|
func (c *DownloadController) ProxyDownload(w http.ResponseWriter, r *http.Request) {
|
||||||
videoUrl, ok := c.getUrlParam(r)
|
videoUrl, ok := c.getUrlParam(r)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -140,15 +136,10 @@ func (c *DownloadController) ProxyDownload(w http.ResponseWriter, r *http.Reques
|
||||||
}
|
}
|
||||||
|
|
||||||
video := videos[index]
|
video := videos[index]
|
||||||
|
format, ok := lo.Find(video.Formats, func(format metadata.Format) bool {
|
||||||
var format *metadata.Format
|
return format.FormatID == formatId
|
||||||
for _, f := range video.Formats {
|
})
|
||||||
if f.FormatID == formatId {
|
if !ok {
|
||||||
format = &f
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if format == nil {
|
|
||||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -156,25 +147,17 @@ func (c *DownloadController) ProxyDownload(w http.ResponseWriter, r *http.Reques
|
||||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s-%s.%s\"", meta.ID, format.Resolution, format.Ext))
|
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s-%s.%s\"", meta.ID, format.Resolution, format.Ext))
|
||||||
if format.Filesize != nil {
|
if format.Filesize != nil {
|
||||||
w.Header().Set("Content-Length", fmt.Sprint(*format.Filesize))
|
w.Header().Set("Content-Length", fmt.Sprint(*format.Filesize))
|
||||||
|
} else if format.FilesizeApprox != nil {
|
||||||
|
w.Header().Set("Content-Length", fmt.Sprint(*format.FilesizeApprox))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(videos) == 1 {
|
if len(videos) == 1 {
|
||||||
index = -1
|
index = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
read, write := io.Pipe()
|
if err := c.ytdl.Download(w, videoUrl, format.FormatID, index); err != nil {
|
||||||
|
|
||||||
go func() {
|
|
||||||
_, err := io.Copy(w, read)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error("Failed to copy", slog.String("error", err.Error()))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := c.ytdl.Download(write, videoUrl, format.FormatID, index); err != nil {
|
|
||||||
slog.Error("Failed to download", slog.String("error", err.Error()))
|
slog.Error("Failed to download", slog.String("error", err.Error()))
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
write.Close()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,25 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/samber/lo"
|
||||||
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Video struct {
|
type Video struct {
|
||||||
Meta *metadata.Metadata
|
Meta *metadata.Metadata
|
||||||
Formats []metadata.Format
|
Formats []metadata.Format
|
||||||
OtherFormats []metadata.Format
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetVideosFromMetadata(meta *metadata.Metadata) []Video {
|
func GetVideosFromMetadata(meta *metadata.Metadata) []Video {
|
||||||
if meta.IsPlaylist() {
|
if meta.IsPlaylist() {
|
||||||
videos := make([]Video, 0, len(meta.Entries))
|
return lo.Map(meta.Entries, func(video metadata.Metadata, _ int) Video {
|
||||||
|
return GetVideosFromMetadata(&video)[0]
|
||||||
for _, entry := range meta.Entries {
|
})
|
||||||
videos = append(videos, GetVideosFromMetadata(&entry)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return videos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
formats := []metadata.Format{}
|
formats := lo.Filter(meta.Formats, func(item metadata.Format, _ int) bool {
|
||||||
otherFormats := []metadata.Format{}
|
return item.ACodec != "none" && item.VCodec != "none" && item.Protocol != "m3u8_native"
|
||||||
|
})
|
||||||
for _, format := range meta.Formats {
|
|
||||||
if format.ACodec != "none" && format.VCodec != "none" && format.Protocol != "m3u8_native" {
|
|
||||||
formats = append(formats, format)
|
|
||||||
} else {
|
|
||||||
otherFormats = append(otherFormats, format)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, j := 0, len(formats)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(formats)-1; i < j; i, j = i+1, j-1 {
|
||||||
formats[i], formats[j] = formats[j], formats[i]
|
formats[i], formats[j] = formats[j], formats[i]
|
||||||
|
@ -38,9 +27,8 @@ func GetVideosFromMetadata(meta *metadata.Metadata) []Video {
|
||||||
|
|
||||||
return []Video{
|
return []Video{
|
||||||
{
|
{
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
Formats: formats,
|
Formats: formats,
|
||||||
OtherFormats: otherFormats,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
app/views.go
20
app/views.go
|
@ -3,7 +3,6 @@ package app
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
@ -40,25 +39,6 @@ var Views = html.New(
|
||||||
"Format": format,
|
"Format": format,
|
||||||
}
|
}
|
||||||
}).
|
}).
|
||||||
WithFunction("sprintf", func(format string, args ...any) string {
|
|
||||||
return fmt.Sprintf(format, args...)
|
|
||||||
}).
|
|
||||||
WithFunction("filesize", func(size *int) string {
|
|
||||||
if size == nil {
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
const unit = 1000
|
|
||||||
if *size < unit {
|
|
||||||
return fmt.Sprintf("%d B", *size)
|
|
||||||
}
|
|
||||||
div, exp := int64(unit), 0
|
|
||||||
for n := *size / unit; n >= unit; n /= unit {
|
|
||||||
div *= unit
|
|
||||||
exp++
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%.1f %cB",
|
|
||||||
float64(*size)/float64(div), "kMGTPE"[exp])
|
|
||||||
}).
|
|
||||||
WithFunctions(reformism.FuncsHTML),
|
WithFunctions(reformism.FuncsHTML),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,62 +2,51 @@
|
||||||
<h1>Download Video</h1>
|
<h1>Download Video</h1>
|
||||||
<h2 class="fs-4 text-muted text-center">{{.Meta.Title}}</h2>
|
<h2 class="fs-4 text-muted text-center">{{.Meta.Title}}</h2>
|
||||||
<p style="font-size: 0.85rem">{{.Url}}</p>
|
<p style="font-size: 0.85rem">{{.Url}}</p>
|
||||||
<a href="{{.BasePath}}/" hx-get="{{.BasePath}}/" hx-trigger="click" hx-target="#main-content"
|
<a
|
||||||
class="btn btn-secondary btn-sm mt-3" style="width: 30rem; max-width: 100%">
|
href="{{.BasePath}}/"
|
||||||
|
hx-get="{{.BasePath}}/"
|
||||||
|
hx-trigger="click"
|
||||||
|
hx-target="#main-content"
|
||||||
|
class="btn btn-secondary btn-sm mt-3"
|
||||||
|
style="width: 30rem; max-width: 100%"
|
||||||
|
>
|
||||||
Download Another Video
|
Download Another Video
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{$root := .}}
|
{{$root := .}} {{range $vidIndex, $video := .Videos}} {{if not (eq $vidIndex
|
||||||
{{range $vidIndex, $video := .Videos}}
|
0)}}
|
||||||
{{if not (eq $vidIndex 0)}}
|
|
||||||
<hr class="mt-5" />
|
<hr class="mt-5" />
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="d-flex flex-column flex-lg-row justify-content-center gap-5 mt-5">
|
<div class="d-flex flex-column flex-lg-row justify-content-center gap-5 mt-5">
|
||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
<img src="{{$video.Meta.Thumbnail}}" alt="{{$video.Meta.Title}}" style="max-height: 25rem; max-width: 100%; margin: 0 auto" />
|
<img
|
||||||
|
src="{{.Meta.Thumbnail}}"
|
||||||
|
alt="{{.Meta.Title}}"
|
||||||
|
style="max-height: 25rem; max-width: 100%; margin: 0 auto"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="downloads flex-lg-grow-1">
|
<div class="downloads flex-lg-grow-1">
|
||||||
{{range $index, $format := $video.Formats}}
|
{{range $index, $format := $video.Formats}}
|
||||||
{{template "format" (map "root" $root "format" $format "label" $format.Format "vidIndex" $vidIndex)}}
|
<div style="font-size: smaller">{{$format.Format}}</div>
|
||||||
{{end}}
|
<div class="flex-grow-1 d-flex gap-3">
|
||||||
</div>
|
<a
|
||||||
</div>
|
class="btn btn-primary flex-grow-1"
|
||||||
{{if gt (len $video.OtherFormats) 0}}
|
download="{{$root.Meta.ID}}-{{$format.Resolution}}.{{$format.Ext}}"
|
||||||
<div class="d-grid my-3">
|
P
|
||||||
<button
|
href="{{$format.Url}}"
|
||||||
type="button"
|
>
|
||||||
class="btn btn-secondary"
|
Download (direct)
|
||||||
data-bs-toggle="collapse"
|
</a>
|
||||||
data-bs-target="#collapse-{{$root.Meta.ID}}-{{$vidIndex}}"
|
<a
|
||||||
aria-expanded="false"
|
class="btn btn-primary flex-grow-1"
|
||||||
aria-controls="collapse-{{$root.Meta.ID}}-{{$vidIndex}}"
|
download="{{$root.Meta.ID}}-{{$format.Resolution}}.{{$format.Ext}}"
|
||||||
>
|
href="{{$root.BasePath}}/download/proxy?url={{queryEscape $root.Url}}&format={{$format.FormatID}}&index={{$vidIndex}}"
|
||||||
See More Formats
|
>
|
||||||
</button>
|
Download (proxied)
|
||||||
</div>
|
</a>
|
||||||
<div id="collapse-{{$root.Meta.ID}}-{{$vidIndex}}" class="collapse">
|
</div>
|
||||||
<div class="downloads d-flex d-md-grid flex-column">
|
|
||||||
{{range $index, $format := $video.OtherFormats}}
|
|
||||||
{{$label := sprintf "ext: %s, resolution: %s, filesize: %s, note: %s" $format.Ext $format.Resolution
|
|
||||||
(filesize $format.Filesize) $format.FormatNote}}
|
|
||||||
{{template "format" (map "root" $root "format" $format "label" $label "vidIndex" $vidIndex)}}
|
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{define "format"}}
|
|
||||||
<div style="font-size: smaller">{{.label}}</div>
|
|
||||||
<div class="flex-grow-1 d-flex gap-3">
|
|
||||||
<a class="btn btn-primary flex-grow-1" download="{{.root.Meta.ID}}-{{.format.Resolution}}.{{.format.Ext}}" P
|
|
||||||
href="{{.format.Url}}">
|
|
||||||
Download (direct)
|
|
||||||
</a>
|
|
||||||
<a class="btn btn-primary flex-grow-1" download="{{.root.Meta.ID}}-{{.format.Resolution}}.{{.format.Ext}}"
|
|
||||||
href="{{.root.BasePath}}/download/proxy?url={{queryEscape .root.Url}}&format={{.format.FormatID}}&index={{.vidIndex}}">
|
|
||||||
Download (proxied)
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
|
@ -5,21 +5,48 @@
|
||||||
with more features and fixes.
|
with more features and fixes.
|
||||||
<br />
|
<br />
|
||||||
View a complete list of supported websites
|
View a complete list of supported websites
|
||||||
<a href="https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md">here</a>.
|
<a href="https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md"
|
||||||
|
>here</a
|
||||||
|
>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form hx-get="{{.BasePath}}/download" hx-trigger="submit" hx-target="#main-content" hx-swap="innerHTML">
|
<form
|
||||||
|
hx-get="{{.BasePath}}/download"
|
||||||
|
hx-trigger="submit"
|
||||||
|
hx-target="#main-content"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="url" class="form-label visually-hidden">Url</label>
|
<label for="url" class="form-label visually-hidden">Url</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="url" name="url" id="url" class="form-control" required
|
<input
|
||||||
placeholder="Enter url here then click download" />
|
type="url"
|
||||||
|
name="url"
|
||||||
|
id="url"
|
||||||
|
class="form-control"
|
||||||
|
required
|
||||||
|
placeholder="Enter url here then click download"
|
||||||
|
/>
|
||||||
{{if .IsSecure}}
|
{{if .IsSecure}}
|
||||||
<button id="paste-button" class="btn btn-outline-secondary" type="button" title="Paste">
|
<button
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
id="paste-button"
|
||||||
style="width: 1.5rem; height: 1.5rem">
|
class="btn btn-outline-secondary"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round"
|
type="button"
|
||||||
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184" />
|
title="Paste"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
style="width: 1.5rem; height: 1.5rem"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -28,7 +55,10 @@
|
||||||
<div class="d-grid">
|
<div class="d-grid">
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
Download
|
Download
|
||||||
<div class="spinner-border spinner-border-sm htmx-indicator ms-1" role="status">
|
<div
|
||||||
|
class="spinner-border spinner-border-sm htmx-indicator ms-1"
|
||||||
|
role="status"
|
||||||
|
>
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span class="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
@ -40,13 +70,22 @@
|
||||||
<span>{{.Error.Message}}</span>
|
<span>{{.Error.Message}}</span>
|
||||||
|
|
||||||
{{if .Error.RetryUrl}}
|
{{if .Error.RetryUrl}}
|
||||||
<button class="btn btn-link btn-sm pt-0 lh-base text-decoration-none" hx-get="/download" hx-trigger="click"
|
<button
|
||||||
hx-target="#main-content" hx-swap="innerHTML" hx-vals='{"url": "{{.Error.RetryUrl}}"}'>
|
class="btn btn-link btn-sm pt-0 lh-base text-decoration-none"
|
||||||
|
hx-get="/download"
|
||||||
|
hx-trigger="click"
|
||||||
|
hx-target="#main-content"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
hx-vals='{"url": "{{.Error.RetryUrl}}"}'
|
||||||
|
>
|
||||||
<span class="text-decoration-underline">Try Again</span>
|
<span class="text-decoration-underline">Try Again</span>
|
||||||
<div class="spinner-border spinner-border-sm htmx-indicator ms-1" role="status">
|
<div
|
||||||
|
class="spinner-border spinner-border-sm htmx-indicator ms-1"
|
||||||
|
role="status"
|
||||||
|
>
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span class="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -1,75 +1,94 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en" class="h-100">
|
<html lang="en" class="h-100">
|
||||||
|
<head>
|
||||||
<head>
|
<meta charset="UTF-8" />
|
||||||
<meta charset="UTF-8" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<title>YTDL Web</title>
|
||||||
<title>YTDL Web</title>
|
<link
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css"
|
||||||
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous" />
|
rel="stylesheet"
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/toastr@2.1.4/build/toastr.min.css"
|
integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ"
|
||||||
integrity="sha256-R91pD48xW+oHbpJYGn5xR0Q7tMhH4xOrWn1QqMRINtA=" crossorigin="anonymous" />
|
crossorigin="anonymous"
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
|
/>
|
||||||
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"
|
<link
|
||||||
defer></script>
|
rel="stylesheet"
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js" defer></script>
|
href="https://cdn.jsdelivr.net/npm/toastr@2.1.4/build/toastr.min.css"
|
||||||
<script src="https://cdn.jsdelivr.net/npm/toastr@2.1.4/build/toastr.min.js"
|
integrity="sha256-R91pD48xW+oHbpJYGn5xR0Q7tMhH4xOrWn1QqMRINtA="
|
||||||
integrity="sha256-Hgwq1OBpJ276HUP9H3VJkSv9ZCGRGQN+JldPJ8pNcUM=" crossorigin="anonymous" defer></script>
|
crossorigin="anonymous"
|
||||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@1.9.4/dist/htmx.min.js"
|
/>
|
||||||
integrity="sha256-XIivRAE99i/eil5P31JNihaDSiix0V40rgmUrCfNTH4=" crossorigin="anonymous"></script>
|
<script
|
||||||
<style>
|
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"
|
||||||
#toast-container>div {
|
integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe"
|
||||||
-moz-box-shadow: none !important;
|
crossorigin="anonymous"
|
||||||
-webkit-box-shadow: none !important;
|
defer
|
||||||
box-shadow: none !important;
|
></script>
|
||||||
-ms-filter: none;
|
<script
|
||||||
filter: none;
|
src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"
|
||||||
opacity: 1;
|
defer
|
||||||
}
|
></script>
|
||||||
|
<script
|
||||||
.downloads {
|
src="https://cdn.jsdelivr.net/npm/toastr@2.1.4/build/toastr.min.js"
|
||||||
display: grid;
|
integrity="sha256-Hgwq1OBpJ276HUP9H3VJkSv9ZCGRGQN+JldPJ8pNcUM="
|
||||||
grid-template-columns: minmax(auto, max-content) auto;
|
crossorigin="anonymous"
|
||||||
gap: 1.5rem;
|
defer
|
||||||
align-items: center;
|
></script>
|
||||||
}
|
<script
|
||||||
|
src="https://cdn.jsdelivr.net/npm/htmx.org@1.9.4/dist/htmx.min.js"
|
||||||
.see-more-btn,
|
integrity="sha256-XIivRAE99i/eil5P31JNihaDSiix0V40rgmUrCfNTH4="
|
||||||
.collapse {
|
crossorigin="anonymous"
|
||||||
grid-column: span 2;
|
></script>
|
||||||
}
|
<style>
|
||||||
</style>
|
#toast-container > div {
|
||||||
</head>
|
-moz-box-shadow: none !important;
|
||||||
|
-webkit-box-shadow: none !important;
|
||||||
<body class="d-flex flex-column h-100" data-bs-theme="dark">
|
box-shadow: none !important;
|
||||||
<div class="flex-shrink-0">
|
-ms-filter: none;
|
||||||
{{template "partials/navbar" .}}
|
filter: none;
|
||||||
<main id="main-content" class="container my-5">{{yield}}</main>
|
opacity: 1;
|
||||||
</div>
|
|
||||||
{{template "partials/footer" .}}
|
|
||||||
<script>
|
|
||||||
/**
|
|
||||||
* @param content {Element}
|
|
||||||
*/
|
|
||||||
function setupPaste(content) {
|
|
||||||
const pasteButton = content.querySelector("#paste-button");
|
|
||||||
const urlField = content.querySelector("#url");
|
|
||||||
|
|
||||||
if (pasteButton) {
|
|
||||||
pasteButton.addEventListener("click", async () => {
|
|
||||||
try {
|
|
||||||
const text = await navigator.clipboard.readText();
|
|
||||||
urlField.value = text;
|
|
||||||
} catch (error) {
|
|
||||||
toastr.error("Failed to paste url from clipboard.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
htmx.onLoad(setupPaste);
|
.downloads {
|
||||||
</script>
|
display: grid;
|
||||||
</body>
|
grid-template-columns: minmax(auto, max-content) auto;
|
||||||
|
gap: 1.5rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
</html>
|
.see-more-btn,
|
||||||
|
.collapse {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="d-flex flex-column h-100" data-bs-theme="dark">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
{{template "partials/navbar" .}}
|
||||||
|
<main id="main-content" class="container my-5">{{yield}}</main>
|
||||||
|
</div>
|
||||||
|
{{template "partials/footer" .}}
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* @param content {Element}
|
||||||
|
*/
|
||||||
|
function setupPaste(content) {
|
||||||
|
const pasteButton = content.querySelector("#paste-button");
|
||||||
|
const urlField = content.querySelector("#url");
|
||||||
|
|
||||||
|
if (pasteButton) {
|
||||||
|
pasteButton.addEventListener("click", async () => {
|
||||||
|
try {
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
urlField.value = text;
|
||||||
|
} catch (error) {
|
||||||
|
toastr.error("Failed to paste url from clipboard.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
htmx.onLoad(setupPaste);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
<div class="d-flex gap-1 align-items-baseline">
|
<div class="d-flex gap-1 align-items-baseline">
|
||||||
Version:
|
Version:
|
||||||
<span class="text-muted">{{.Version}}</span>
|
<span class="text-muted">{{.Version}}</span>
|
||||||
<span class="text-muted text-nowrap" style="font-size: smaller">(Build: {{.Build}})</span>
|
<span class="text-muted text-nowrap" style="font-size: smaller"
|
||||||
|
>(Build: {{.Build}})</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-1 align-items-baseline text-nowrap">
|
<div class="d-flex gap-1 align-items-baseline text-nowrap">
|
||||||
yt-dlp version: <span class="text-muted">{{.BinaryVersion}}</span>
|
yt-dlp version: <span class="text-muted">{{.BinaryVersion}}</span>
|
||||||
|
@ -13,8 +15,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-2 col-md justify-content-center">
|
<div class="d-flex gap-2 col-md justify-content-center">
|
||||||
<a href="https://git.fifitido.net/apps/ytdl-web">Git Repository</a>
|
<a href="https://git.fifitido.net/apps/ytdl-web">Git Repository</a>
|
||||||
<span class="text-muted">© 2024 FiFiTiDo</span>
|
<span class="text-muted">© 2023 FiFiTiDo</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="/" class="navbar-brand">YTDL Web</a>
|
<a href="/" class="navbar-brand">YTDL Web</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
|
||||||
*/
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
// completionCmd represents the completion command
|
|
||||||
var completionCmd = &cobra.Command{
|
|
||||||
Use: "completion [bash|zsh|fish|powershell]",
|
|
||||||
Short: "Generate completion script",
|
|
||||||
Long: fmt.Sprintf(`To load completions:
|
|
||||||
|
|
||||||
Bash:
|
|
||||||
|
|
||||||
$ source <(%[1]s completion bash)
|
|
||||||
|
|
||||||
# To load completions for each session, execute once:
|
|
||||||
# Linux:
|
|
||||||
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
|
|
||||||
# macOS:
|
|
||||||
$ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
|
|
||||||
|
|
||||||
Zsh:
|
|
||||||
|
|
||||||
# If shell completion is not already enabled in your environment,
|
|
||||||
# you will need to enable it. You can execute the following once:
|
|
||||||
|
|
||||||
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
|
|
||||||
|
|
||||||
# To load completions for each session, execute once:
|
|
||||||
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
|
|
||||||
|
|
||||||
# You will need to start a new shell for this setup to take effect.
|
|
||||||
|
|
||||||
fish:
|
|
||||||
|
|
||||||
$ %[1]s completion fish | source
|
|
||||||
|
|
||||||
# To load completions for each session, execute once:
|
|
||||||
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
|
|
||||||
|
|
||||||
PowerShell:
|
|
||||||
|
|
||||||
PS> %[1]s completion powershell | Out-String | Invoke-Expression
|
|
||||||
|
|
||||||
# To load completions for every new session, run:
|
|
||||||
PS> %[1]s completion powershell > %[1]s.ps1
|
|
||||||
# and source this file from your PowerShell profile.
|
|
||||||
`, rootCmd.Root().Name()),
|
|
||||||
DisableFlagsInUseLine: true,
|
|
||||||
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
|
|
||||||
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
switch args[0] {
|
|
||||||
case "bash":
|
|
||||||
cmd.Root().GenBashCompletion(os.Stdout)
|
|
||||||
case "zsh":
|
|
||||||
cmd.Root().GenZshCompletion(os.Stdout)
|
|
||||||
case "fish":
|
|
||||||
cmd.Root().GenFishCompletion(os.Stdout, true)
|
|
||||||
case "powershell":
|
|
||||||
cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(completionCmd)
|
|
||||||
|
|
||||||
// Here you will define your flags and configuration settings.
|
|
||||||
|
|
||||||
// Cobra supports Persistent Flags which will work for this command
|
|
||||||
// and all subcommands, e.g.:
|
|
||||||
// completionCmd.PersistentFlags().String("foo", "", "A help for foo")
|
|
||||||
|
|
||||||
// Cobra supports local flags which will only run when this command
|
|
||||||
// is called directly, e.g.:
|
|
||||||
// completionCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
|
||||||
}
|
|
68
cmd/root.go
68
cmd/root.go
|
@ -1,16 +1,20 @@
|
||||||
/*
|
/*
|
||||||
Copyright © 2024 Evan Fiordeliso <evan.fiordeliso@gmail.com>
|
Copyright © 2023 Evan Fiordeliso <evan.fiordeliso@gmail.com>
|
||||||
*/
|
*/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/dgraph-io/badger/v2"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"go.fifitido.net/ytdl-web/app/controllers"
|
||||||
"go.fifitido.net/ytdl-web/config"
|
"go.fifitido.net/ytdl-web/config"
|
||||||
|
"go.fifitido.net/ytdl-web/pkg/server"
|
||||||
|
"go.fifitido.net/ytdl-web/pkg/utils"
|
||||||
|
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
||||||
|
"go.fifitido.net/ytdl-web/pkg/ytdl/cache"
|
||||||
"golang.org/x/exp/slog"
|
"golang.org/x/exp/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,13 +25,47 @@ var (
|
||||||
rootCmd = &cobra.Command{
|
rootCmd = &cobra.Command{
|
||||||
Use: "ytdl-web",
|
Use: "ytdl-web",
|
||||||
Short: "A web frontend for yt-dlp",
|
Short: "A web frontend for yt-dlp",
|
||||||
Long: `YTDL Web is a web application that grabs the links to videos
|
Long: `YTDL Web
|
||||||
from over a thousand websites using the yt-dlp project under the hood.`,
|
|
||||||
|
A web application that grabs the links to videos from over a
|
||||||
|
thousand websites using the yt-dlp project under the hood.`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
logger := slog.Default()
|
||||||
|
|
||||||
|
db, err := badger.Open(
|
||||||
|
badger.
|
||||||
|
DefaultOptions(cfg.Cache.DirPath).
|
||||||
|
WithLogger(utils.NewBadgerLogger(logger.With("module", "badger"))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
cache := cache.NewDefaultMetadataCache(db)
|
||||||
|
ytdl := ytdl.NewYtdl(cfg, slog.Default(), cache)
|
||||||
|
|
||||||
|
s := server.New(
|
||||||
|
server.
|
||||||
|
DefaultOptions().
|
||||||
|
WithListenAddr(viper.GetString("http.listen")).
|
||||||
|
WithListenPort(viper.GetInt("http.port")).
|
||||||
|
WithLogger(logger.With("module", "server")),
|
||||||
|
)
|
||||||
|
|
||||||
|
s.MountController("/", controllers.NewHomeController(ytdl))
|
||||||
|
s.MountController("/download", controllers.NewDownloadController(ytdl))
|
||||||
|
|
||||||
|
return s.ListenAndServe()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func Execute() error {
|
func Execute() {
|
||||||
return rootCmd.Execute()
|
err := rootCmd.Execute()
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -60,16 +98,14 @@ func initConfig() {
|
||||||
cfg, err = config.LoadConfig()
|
cfg, err = config.LoadConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
notFound := &viper.ConfigFileNotFoundError{}
|
if err != nil {
|
||||||
switch {
|
slog.Error("Error loading configuration", slog.String("error", err.Error()))
|
||||||
case err != nil && !errors.As(err, notFound):
|
os.Exit(1)
|
||||||
cobra.CheckErr(err)
|
|
||||||
case err != nil && errors.As(err, notFound):
|
|
||||||
// The config file is optional, we shouldn't exit when the config is not found
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initLogging()
|
||||||
|
|
||||||
|
slog.Info("Configuration loaded")
|
||||||
}
|
}
|
||||||
|
|
||||||
func initLogging() {
|
func initLogging() {
|
||||||
|
|
68
cmd/serve.go
68
cmd/serve.go
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright © 2024 Evan Fiordeliso <evan.fiordeliso@gmail.com>
|
|
||||||
*/
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/dgraph-io/badger/v2"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.fifitido.net/ytdl-web/app/controllers"
|
|
||||||
"go.fifitido.net/ytdl-web/pkg/server"
|
|
||||||
"go.fifitido.net/ytdl-web/pkg/utils"
|
|
||||||
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
|
||||||
"go.fifitido.net/ytdl-web/pkg/ytdl/cache"
|
|
||||||
"golang.org/x/exp/slog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
serveCmd = &cobra.Command{
|
|
||||||
Use: "serve",
|
|
||||||
Short: "Serve the ytdl-web application",
|
|
||||||
Long: `Serve the ytdl-web application`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
initLogging()
|
|
||||||
logger := slog.Default()
|
|
||||||
|
|
||||||
db, err := badger.Open(
|
|
||||||
badger.
|
|
||||||
DefaultOptions(cfg.Cache.DirPath).
|
|
||||||
WithLogger(utils.NewBadgerLogger(logger.With("module", "badger"))),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
cache := cache.NewDefaultMetadataCache(db)
|
|
||||||
ytdl := ytdl.NewYtdl(cfg, slog.Default(), cache)
|
|
||||||
|
|
||||||
s := server.New(
|
|
||||||
server.
|
|
||||||
DefaultOptions().
|
|
||||||
WithListenAddr(viper.GetString("http.listen")).
|
|
||||||
WithListenPort(viper.GetInt("http.port")).
|
|
||||||
WithLogger(logger.With("module", "server")),
|
|
||||||
)
|
|
||||||
|
|
||||||
s.MountController("/", controllers.NewHomeController(ytdl))
|
|
||||||
s.MountController("/download", controllers.NewDownloadController(ytdl))
|
|
||||||
|
|
||||||
return s.ListenAndServe()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(serveCmd)
|
|
||||||
|
|
||||||
// Here you will define your flags and configuration settings.
|
|
||||||
|
|
||||||
// Cobra supports Persistent Flags which will work for this command
|
|
||||||
// and all subcommands, e.g.:
|
|
||||||
// completionCmd.PersistentFlags().String("foo", "", "A help for foo")
|
|
||||||
|
|
||||||
// Cobra supports local flags which will only run when this command
|
|
||||||
// is called directly, e.g.:
|
|
||||||
// completionCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@ package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -11,11 +10,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Env string `mapstructure:"env"`
|
Env string `mapstructure:"env"`
|
||||||
Ytdlp ConfigYtdlp `mapstructure:"ytdlp"`
|
BinaryPath string `mapstructure:"binaryPath"`
|
||||||
HTTP ConfigHTTP `mapstructure:"http"`
|
HTTP ConfigHTTP `mapstructure:"http"`
|
||||||
Cache ConfigCache `mapstructure:"cache"`
|
Cache ConfigCache `mapstructure:"cache"`
|
||||||
Cookies ConfigCookies `mapstructure:"cookies"`
|
Cookies ConfigCookies `mapstructure:"cookies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) IsProduction() bool {
|
func (c *Config) IsProduction() bool {
|
||||||
|
@ -30,10 +29,6 @@ func (c *Config) IsStaging() bool {
|
||||||
return c.Env == "Staging"
|
return c.Env == "Staging"
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigYtdlp struct {
|
|
||||||
BinaryPath string `mapstructure:"binaryPath"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigHTTP struct {
|
type ConfigHTTP struct {
|
||||||
Port int `mapstructure:"port"`
|
Port int `mapstructure:"port"`
|
||||||
Listen string `mapstructure:"listen"`
|
Listen string `mapstructure:"listen"`
|
||||||
|
@ -61,8 +56,8 @@ type ConfigCookiesFromBrowser struct {
|
||||||
|
|
||||||
func DefaultConfig() *Config {
|
func DefaultConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
Env: "Production",
|
Env: "Production",
|
||||||
Ytdlp: ConfigYtdlp{BinaryPath: "yt-dlp"},
|
BinaryPath: "yt-dlp",
|
||||||
HTTP: ConfigHTTP{
|
HTTP: ConfigHTTP{
|
||||||
Port: 8080,
|
Port: 8080,
|
||||||
Listen: "127.0.0.1",
|
Listen: "127.0.0.1",
|
||||||
|
@ -81,44 +76,46 @@ func DefaultConfig() *Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadConfig(paths ...string) (*Config, error) {
|
func LoadConfig(paths ...string) (*Config, error) {
|
||||||
viper.SetEnvPrefix("YTDL")
|
v := viper.New()
|
||||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
||||||
viper.AutomaticEnv()
|
|
||||||
|
|
||||||
viper.SetConfigName("config")
|
v.SetEnvPrefix("YTDL")
|
||||||
viper.SetConfigType("yaml")
|
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||||
|
v.AutomaticEnv()
|
||||||
|
|
||||||
|
v.SetConfigName("config")
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
|
||||||
if len(paths) > 0 {
|
if len(paths) > 0 {
|
||||||
for _, p := range paths {
|
for _, path := range paths {
|
||||||
viper.AddConfigPath(path.Dir(p))
|
v.AddConfigPath(path)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
envDir := os.Getenv("YTDL_CONFIGDIR")
|
envDir := os.Getenv("YTDL_CONFIGDIR")
|
||||||
if envDir != "" {
|
if envDir != "" {
|
||||||
viper.AddConfigPath(envDir)
|
v.AddConfigPath(envDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
viper.AddConfigPath(".")
|
v.AddConfigPath(".")
|
||||||
|
|
||||||
homeDir, err := os.UserHomeDir()
|
homeDir, err := os.UserHomeDir()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
viper.AddConfigPath(homeDir + "/.config/ytdl-web")
|
v.AddConfigPath(homeDir + "/.config/ytdl-web")
|
||||||
}
|
}
|
||||||
|
|
||||||
viper.AddConfigPath(xdg.ConfigHome + "/ytdl-web")
|
v.AddConfigPath(xdg.ConfigHome + "/ytdl-web")
|
||||||
for _, dir := range xdg.ConfigDirs {
|
for _, dir := range xdg.ConfigDirs {
|
||||||
viper.AddConfigPath(dir + "/ytdl-web")
|
v.AddConfigPath(dir + "/ytdl-web")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := viper.ReadInConfig(); err != nil {
|
if err := v.ReadInConfig(); err != nil {
|
||||||
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config := DefaultConfig()
|
config := DefaultConfig()
|
||||||
if err := viper.Unmarshal(config); err != nil {
|
if err := v.Unmarshal(config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
devenv.lock
44
devenv.lock
|
@ -3,11 +3,11 @@
|
||||||
"devenv": {
|
"devenv": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "src/modules",
|
"dir": "src/modules",
|
||||||
"lastModified": 1708141957,
|
"lastModified": 1689175844,
|
||||||
"narHash": "sha256-IWkw+jsVpu7HFNPbOTJaQeMYQ5/eh7ZVScPvtlSo8vc=",
|
"narHash": "sha256-+ZAcAnogqNXz5P2/NiZonmgUiv+vCC7/swiSepyTulc=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "devenv",
|
"repo": "devenv",
|
||||||
"rev": "40b567388381137a3c49acdff5f4b6946d645a5f",
|
"rev": "db59403d5bdad71dce137705ed7cb926681e5f95",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -20,11 +20,11 @@
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1696426674,
|
"lastModified": 1673956053,
|
||||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -38,11 +38,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1701680307,
|
"lastModified": 1685518550,
|
||||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -59,11 +59,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1703887061,
|
"lastModified": 1660459072,
|
||||||
"narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=",
|
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "gitignore.nix",
|
"repo": "gitignore.nix",
|
||||||
"rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5",
|
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -74,11 +74,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1708151420,
|
"lastModified": 1689168768,
|
||||||
"narHash": "sha256-MGT/4aGCWQPQiu6COqJdCj9kSpLPiShgbwpbC38YXC8=",
|
"narHash": "sha256-mCw3LPg2jJkapvJpkd1IZ8k0IJlSG2ECvz3vcOAu+Uo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "6e2f00c83911461438301db0dba5281197fe4b3a",
|
"rev": "6fd9edc94426a3c050ad589c8f033b5ca55454c7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -90,16 +90,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs-stable": {
|
"nixpkgs-stable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1704874635,
|
"lastModified": 1685801374,
|
||||||
"narHash": "sha256-YWuCrtsty5vVZvu+7BchAxmcYzTMfolSPP5io8+WYCg=",
|
"narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "3dc440faeee9e889fe2d1b4d25ad0f430d449356",
|
"rev": "c37ca420157f4abc31e26f436c1145f8951ff373",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-23.11",
|
"ref": "nixos-23.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -115,11 +115,11 @@
|
||||||
"nixpkgs-stable": "nixpkgs-stable"
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1708018599,
|
"lastModified": 1688596063,
|
||||||
"narHash": "sha256-M+Ng6+SePmA8g06CmUZWi1AjG2tFBX9WCXElBHEKnyM=",
|
"narHash": "sha256-9t7RxBiKWHygsqXtiNATTJt4lim/oSYZV3RG8OjDDng=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "pre-commit-hooks.nix",
|
"repo": "pre-commit-hooks.nix",
|
||||||
"rev": "5df5a70ad7575f6601d91f0efec95dd9bc619431",
|
"rev": "c8d18ba345730019c3faf412c96a045ade171895",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# https://devenv.sh/basics/
|
# https://devenv.sh/basics/
|
||||||
env.NAME = "ytdl-web";
|
env.NAME = "ytdl-web";
|
||||||
env.BINARY_OUT = "./out/ytdl-web";
|
env.BINARY_OUT = "./out/ytdl-web";
|
||||||
env.VERSION = "v1.2.3";
|
env.VERSION = "v1.1.4";
|
||||||
env.VERSION_PKG = "go.fifitido.net/ytdl-web/version";
|
env.VERSION_PKG = "go.fifitido.net/ytdl-web/version";
|
||||||
env.DOCKER_REGISTRY = "git.fifitido.net";
|
env.DOCKER_REGISTRY = "git.fifitido.net";
|
||||||
env.DOCKER_ORG = "apps";
|
env.DOCKER_ORG = "apps";
|
||||||
|
@ -22,7 +22,6 @@
|
||||||
buildkit
|
buildkit
|
||||||
docker-buildx
|
docker-buildx
|
||||||
yt-dlp
|
yt-dlp
|
||||||
cobra-cli
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# https://devenv.sh/scripts/
|
# https://devenv.sh/scripts/
|
757
flake.lock
757
flake.lock
|
@ -1,757 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"cachix": {
|
|
||||||
"inputs": {
|
|
||||||
"devenv": "devenv_2",
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv",
|
|
||||||
"flake-compat"
|
|
||||||
],
|
|
||||||
"git-hooks": [
|
|
||||||
"devenv",
|
|
||||||
"pre-commit-hooks"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1726520618,
|
|
||||||
"narHash": "sha256-jOsaBmJ/EtX5t/vbylCdS7pWYcKGmWOKg4QKUzKr6dA=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "cachix",
|
|
||||||
"rev": "695525f9086542dfb09fde0871dbf4174abbf634",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "cachix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cachix_2": {
|
|
||||||
"inputs": {
|
|
||||||
"devenv": "devenv_3",
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"flake-compat"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"pre-commit-hooks": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"pre-commit-hooks"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1712055811,
|
|
||||||
"narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "cachix",
|
|
||||||
"rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "cachix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"devenv": {
|
|
||||||
"inputs": {
|
|
||||||
"cachix": "cachix",
|
|
||||||
"flake-compat": "flake-compat_2",
|
|
||||||
"nix": "nix_3",
|
|
||||||
"nixpkgs": "nixpkgs_3",
|
|
||||||
"pre-commit-hooks": "pre-commit-hooks_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1730890834,
|
|
||||||
"narHash": "sha256-ogmpmsPOlX4qeWVW4NZkTd0Lx8V4rvnjwlgOX7WnTZo=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv",
|
|
||||||
"rev": "c5353d1a0483b8f0dc15933de91c6b1b9a892831",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"devenv_2": {
|
|
||||||
"inputs": {
|
|
||||||
"cachix": "cachix_2",
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"flake-compat"
|
|
||||||
],
|
|
||||||
"nix": "nix_2",
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"pre-commit-hooks": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"git-hooks"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1723156315,
|
|
||||||
"narHash": "sha256-0JrfahRMJ37Rf1i0iOOn+8Z4CLvbcGNwa2ChOAVrp/8=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv",
|
|
||||||
"rev": "ff5eb4f2accbcda963af67f1a1159e3f6c7f5f91",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"devenv_3": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"flake-compat"
|
|
||||||
],
|
|
||||||
"nix": "nix",
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"poetry2nix": "poetry2nix",
|
|
||||||
"pre-commit-hooks": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"pre-commit-hooks"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1708704632,
|
|
||||||
"narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv",
|
|
||||||
"rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"ref": "python-rewrite",
|
|
||||||
"repo": "devenv",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-compat": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673956053,
|
|
||||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-compat_2": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1696426674,
|
|
||||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-parts": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": [
|
|
||||||
"devenv",
|
|
||||||
"nix",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1712014858,
|
|
||||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-parts_2": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1730504689,
|
|
||||||
"narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "506278e768c2a08bec68eb62932193e341f55c90",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "flake-parts",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1689068808,
|
|
||||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1667395993,
|
|
||||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_3": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1710146030,
|
|
||||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gitignore": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"pre-commit-hooks",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1709087332,
|
|
||||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libgit2": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1697646580,
|
|
||||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
|
||||||
"owner": "libgit2",
|
|
||||||
"repo": "libgit2",
|
|
||||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "libgit2",
|
|
||||||
"repo": "libgit2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mk-shell-bin": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1677004959,
|
|
||||||
"narHash": "sha256-/uEkr1UkJrh11vD02aqufCxtbF5YnhRTIKlx5kyvf+I=",
|
|
||||||
"owner": "rrbutani",
|
|
||||||
"repo": "nix-mk-shell-bin",
|
|
||||||
"rev": "ff5d8bd4d68a347be5042e2f16caee391cd75887",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "rrbutani",
|
|
||||||
"repo": "nix-mk-shell-bin",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat",
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"nixpkgs-regression": "nixpkgs-regression"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1712911606,
|
|
||||||
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
|
|
||||||
"owner": "domenkozar",
|
|
||||||
"repo": "nix",
|
|
||||||
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "domenkozar",
|
|
||||||
"ref": "devenv-2.21",
|
|
||||||
"repo": "nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix-github-actions": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"poetry2nix",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1688870561,
|
|
||||||
"narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nix-github-actions",
|
|
||||||
"rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nix-github-actions",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix2container": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils_3",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1730479402,
|
|
||||||
"narHash": "sha256-79NLeNjpCa4mSasmFsE3QA6obURezF0TUO5Pm+1daog=",
|
|
||||||
"owner": "nlewo",
|
|
||||||
"repo": "nix2container",
|
|
||||||
"rev": "5fb215a1564baa74ce04ad7f903d94ad6617e17a",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nlewo",
|
|
||||||
"repo": "nix2container",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix_2": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"flake-compat"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"nixpkgs-regression": "nixpkgs-regression_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1712911606,
|
|
||||||
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
|
|
||||||
"owner": "domenkozar",
|
|
||||||
"repo": "nix",
|
|
||||||
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "domenkozar",
|
|
||||||
"ref": "devenv-2.21",
|
|
||||||
"repo": "nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix_3": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv",
|
|
||||||
"flake-compat"
|
|
||||||
],
|
|
||||||
"flake-parts": "flake-parts",
|
|
||||||
"libgit2": "libgit2",
|
|
||||||
"nixpkgs": "nixpkgs_2",
|
|
||||||
"nixpkgs-23-11": "nixpkgs-23-11",
|
|
||||||
"nixpkgs-regression": "nixpkgs-regression_3",
|
|
||||||
"pre-commit-hooks": "pre-commit-hooks"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1727438425,
|
|
||||||
"narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=",
|
|
||||||
"owner": "domenkozar",
|
|
||||||
"repo": "nix",
|
|
||||||
"rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "domenkozar",
|
|
||||||
"ref": "devenv-2.24",
|
|
||||||
"repo": "nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692808169,
|
|
||||||
"narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "9201b5ff357e781bf014d0330d18555695df7ba8",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-23-11": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1717159533,
|
|
||||||
"narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-lib": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1730504152,
|
|
||||||
"narHash": "sha256-lXvH/vOfb4aGYyvFmZK/HlsNsr/0CVWlwYvo2rxJk3s=",
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-regression": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1643052045,
|
|
||||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-regression_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1643052045,
|
|
||||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-regression_3": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1643052045,
|
|
||||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-stable": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1720386169,
|
|
||||||
"narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "194846768975b7ad2c4988bdb82572c00222c0d7",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-24.05",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1717432640,
|
|
||||||
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "release-24.05",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_3": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1716977621,
|
|
||||||
"narHash": "sha256-Q1UQzYcMJH4RscmpTkjlgqQDX5yi1tZL0O345Ri6vXQ=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv-nixpkgs",
|
|
||||||
"rev": "4267e705586473d3e5c8d50299e71503f16a6fb6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"ref": "rolling",
|
|
||||||
"repo": "devenv-nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_4": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1716977621,
|
|
||||||
"narHash": "sha256-Q1UQzYcMJH4RscmpTkjlgqQDX5yi1tZL0O345Ri6vXQ=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "devenv-nixpkgs",
|
|
||||||
"rev": "4267e705586473d3e5c8d50299e71503f16a6fb6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"ref": "rolling",
|
|
||||||
"repo": "devenv-nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"poetry2nix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nix-github-actions": "nix-github-actions",
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"cachix",
|
|
||||||
"devenv",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692876271,
|
|
||||||
"narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "poetry2nix",
|
|
||||||
"rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "poetry2nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pre-commit-hooks": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv",
|
|
||||||
"nix"
|
|
||||||
],
|
|
||||||
"flake-utils": "flake-utils_2",
|
|
||||||
"gitignore": [
|
|
||||||
"devenv",
|
|
||||||
"nix"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"nix",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"nixpkgs-stable": [
|
|
||||||
"devenv",
|
|
||||||
"nix",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1712897695,
|
|
||||||
"narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pre-commit-hooks_2": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": [
|
|
||||||
"devenv",
|
|
||||||
"flake-compat"
|
|
||||||
],
|
|
||||||
"gitignore": "gitignore",
|
|
||||||
"nixpkgs": [
|
|
||||||
"devenv",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"nixpkgs-stable": "nixpkgs-stable"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1726745158,
|
|
||||||
"narHash": "sha256-D5AegvGoEjt4rkKedmxlSEmC+nNLMBPWFxvmYnVLhjk=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"rev": "4e743a6920eab45e8ba0fbe49dc459f1423a4b74",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"devenv": "devenv",
|
|
||||||
"flake-parts": "flake-parts_2",
|
|
||||||
"mk-shell-bin": "mk-shell-bin",
|
|
||||||
"nix2container": "nix2container",
|
|
||||||
"nixpkgs": "nixpkgs_4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
56
flake.nix
56
flake.nix
|
@ -1,56 +0,0 @@
|
||||||
{
|
|
||||||
description = "Description for the project";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling";
|
|
||||||
devenv.url = "github:cachix/devenv";
|
|
||||||
nix2container.url = "github:nlewo/nix2container";
|
|
||||||
nix2container.inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
mk-shell-bin.url = "github:rrbutani/nix-mk-shell-bin";
|
|
||||||
};
|
|
||||||
|
|
||||||
nixConfig = {
|
|
||||||
extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw=";
|
|
||||||
extra-substituters = "https://devenv.cachix.org";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = inputs@{ self, flake-parts, ... }:
|
|
||||||
let
|
|
||||||
version = "1.2.0";
|
|
||||||
rev = if (self ? rev) then self.rev else self.dirtyRev;
|
|
||||||
in
|
|
||||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
|
||||||
imports = [
|
|
||||||
inputs.devenv.flakeModule
|
|
||||||
];
|
|
||||||
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
|
|
||||||
|
|
||||||
perSystem = { config, self', inputs', pkgs, system, ... }: {
|
|
||||||
# Per-system attributes can be defined here. The self' and inputs'
|
|
||||||
# module parameters provide easy access to attributes of the same
|
|
||||||
# system.
|
|
||||||
|
|
||||||
# needed for devenv up
|
|
||||||
packages.devenv-up = self'.devShells.default.config.procfileScript;
|
|
||||||
|
|
||||||
packages.default = pkgs.callPackage ./nix/package.nix { inherit rev version; };
|
|
||||||
|
|
||||||
devenv.shells.default = {
|
|
||||||
name = "ytdl-web";
|
|
||||||
|
|
||||||
imports = [
|
|
||||||
./nix/devenv.nix
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
flake = {
|
|
||||||
# The usual flake attributes can be defined here, including system-
|
|
||||||
# agnostic ones like nixosModule and system-enumerating ones, although
|
|
||||||
# those are more easily expressed in perSystem.
|
|
||||||
|
|
||||||
nixosModules.default = import ./nix/module.nix;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
3
go.mod
3
go.mod
|
@ -1,12 +1,13 @@
|
||||||
module go.fifitido.net/ytdl-web
|
module go.fifitido.net/ytdl-web
|
||||||
|
|
||||||
go 1.22
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/adrg/xdg v0.4.0
|
github.com/adrg/xdg v0.4.0
|
||||||
github.com/dgraph-io/badger/v2 v2.2007.4
|
github.com/dgraph-io/badger/v2 v2.2007.4
|
||||||
github.com/go-chi/chi/v5 v5.0.10
|
github.com/go-chi/chi/v5 v5.0.10
|
||||||
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73
|
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73
|
||||||
|
github.com/samber/lo v1.38.1
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
github.com/spf13/viper v1.10.0
|
github.com/spf13/viper v1.10.0
|
||||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
|
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
|
||||||
|
|
42
go.sum
42
go.sum
|
@ -1,14 +1,22 @@
|
||||||
|
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||||
|
cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
@ -23,11 +31,15 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC
|
||||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
|
||||||
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
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/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
@ -37,13 +49,22 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||||
|
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||||
|
github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
||||||
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73 h1:Shcv21tstWAyUkKxbn5bTARYej9sgEgFgTRxUPk1J8o=
|
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73 h1:Shcv21tstWAyUkKxbn5bTARYej9sgEgFgTRxUPk1J8o=
|
||||||
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73/go.mod h1:i2jduFeVras6pm8GnBWdfVKj97mGEXJogjMHzyJhukY=
|
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73/go.mod h1:i2jduFeVras6pm8GnBWdfVKj97mGEXJogjMHzyJhukY=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
|
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
|
||||||
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
@ -56,10 +77,14 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
||||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
@ -72,6 +97,9 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||||
|
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||||
|
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
@ -102,15 +130,22 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||||
|
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
|
||||||
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
|
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
|
||||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -119,12 +154,19 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
|
||||||
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||||
|
|
12
main.go
12
main.go
|
@ -1,16 +1,10 @@
|
||||||
/*
|
/*
|
||||||
Copyright © 2024 Evan Fiordeliso <evan.fiordeliso@gmail.com>
|
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||||
*/
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import "go.fifitido.net/ytdl-web/cmd"
|
||||||
"os"
|
|
||||||
|
|
||||||
"go.fifitido.net/ytdl-web/cmd"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := cmd.Execute(); err != nil {
|
cmd.Execute()
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
229
nix/module.nix
229
nix/module.nix
|
@ -1,229 +0,0 @@
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
let
|
|
||||||
inherit (lib.options) mkOption mkEnableOption mkPackageOption;
|
|
||||||
inherit (lib.modules) mkIf;
|
|
||||||
inherit (lib.types) str enum int path submodule nullOr bool;
|
|
||||||
|
|
||||||
cfg = config.services.ytdl-web;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.services.ytdl-web = {
|
|
||||||
enable = mkEnableOption "ytdl-web";
|
|
||||||
package = mkPackageOption pkgs "ytdl-web" { };
|
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = str;
|
|
||||||
default = "ytdl-web";
|
|
||||||
description = ''
|
|
||||||
The user account ytdl-web will run under.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
group = mkOption {
|
|
||||||
type = str;
|
|
||||||
default = "ytdl-web";
|
|
||||||
description = ''
|
|
||||||
The group ytdl-web will run under.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
appEnvironment = mkOption {
|
|
||||||
type = enum [ "Development" "Staging" "Production" ];
|
|
||||||
default = "Production";
|
|
||||||
description = ''
|
|
||||||
The application environment mode.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
ytdlPackage = mkPackageOption pkgs "yt-dlp" { };
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = int;
|
|
||||||
default = 8080;
|
|
||||||
description = ''
|
|
||||||
The tcp port for the web server to listen on.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
listen = mkOption {
|
|
||||||
type = str;
|
|
||||||
default = "0.0.0.0";
|
|
||||||
example = "127.0.0.1";
|
|
||||||
description = ''
|
|
||||||
The address for the web server to listen on.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
openFirewall = mkOption {
|
|
||||||
type = bool;
|
|
||||||
default = false;
|
|
||||||
example = literalExpression "true";
|
|
||||||
description = ''
|
|
||||||
Open ports in the firewall for the ytdl-web server.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
basePath = mkOption {
|
|
||||||
type = str;
|
|
||||||
default = "/";
|
|
||||||
example = "/ytdl-web";
|
|
||||||
description = ''
|
|
||||||
The base path that the web application is hosted under.
|
|
||||||
Useful for reverse-proxies that proxy the app with a path prefix.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
cacheTTL = mkOption {
|
|
||||||
type = str;
|
|
||||||
default = "1h";
|
|
||||||
example = "2m";
|
|
||||||
description = ''
|
|
||||||
How long to keep cached metadata for.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of decimal numbers,
|
|
||||||
each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
cacheDir = mkOption {
|
|
||||||
type = path;
|
|
||||||
default = "/var/cache/ytdl-web";
|
|
||||||
example = "/tmp/ytdl-web";
|
|
||||||
description = ''
|
|
||||||
The directory containing the ytdl metadata cache.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
cookies = mkOption {
|
|
||||||
type = submodule {
|
|
||||||
options = {
|
|
||||||
enable = mkEnableOption "ytdl cookies";
|
|
||||||
|
|
||||||
file = mkOption {
|
|
||||||
type = nullOr path;
|
|
||||||
default = null;
|
|
||||||
example = "/etc/ytdl-web/cookies.txt";
|
|
||||||
description = ''
|
|
||||||
The file that contains the netscape formatted cookies.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
fromBrowser = mkOption {
|
|
||||||
description = ''
|
|
||||||
Settings for obtaining cookies from a local browser's cookie storage.
|
|
||||||
'';
|
|
||||||
|
|
||||||
type = submodule {
|
|
||||||
options = {
|
|
||||||
browser = mkOption {
|
|
||||||
type = nullOr (enum [ "brave" "chrome" "chromium" "edge" "firefox" "opera" "safari" "vivaldi" ]);
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The name of the browser to load cookies from.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
keyring = mkOption {
|
|
||||||
type = nullOr (enum [ "basictext" "gnomekeyring" "kwallet" ]);
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The name of the keyring to use to decrypt cookies when using the chromium browser.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
profile = mkOption {
|
|
||||||
type = nullOr str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The name of the browser profile to load the cookies from.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
container = mkOption {
|
|
||||||
type = nullOr str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The container name to load the cookies from when using the firefox browser.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = cfg.cookies.file != null && cfg.cookies.fromBrowser.browser != null;
|
|
||||||
message = "The `services.ytdl-web.cookies.file` and `services.ytdl-web.cookies.fromBrowser.browser` options are mutually exclusive.";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = cfg.cookies.fromBrowser.browser != null &&
|
|
||||||
!(builtins.elem cfg.cookies.fromBrowser.browser [ "brave" "chrome" "chromium" "edge" "opera" "vivaldi" ]) &&
|
|
||||||
cfg.cookies.fromBrowser.keyring != null;
|
|
||||||
message = "The `services.ytdl-web.cookies.fromBrowser.keyring` only functions with a chromium-based browser.";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = cfg.cookies.fromBrowser.browser != null &&
|
|
||||||
cfg.cookies.fromBrowser.browser != "firefox" &&
|
|
||||||
cfg.cookies.fromBrowser.container != null;
|
|
||||||
message = "The `services.ytdl-web.cookies.fromBrowser.container` only functions with the firefox browser.";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services.ytdl-web = {
|
|
||||||
description = "ytdl-web";
|
|
||||||
after = [ "networking.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
YTDL_ENV = cfg.appEnvironment;
|
|
||||||
YTDL_BINARY_PATH = toString cfg.ytdlPackage;
|
|
||||||
YTDL_HTTP_PORT = toString cfg.port;
|
|
||||||
YTDL_HTTP_LISTEN = cfg.listen;
|
|
||||||
YTDL_HTTP_BASEPATH = cfg.basePath;
|
|
||||||
YTDL_CACHE_TTL = cfg.cacheTTL;
|
|
||||||
YTDL_CACHE_DIRPATH = cfg.cacheDir;
|
|
||||||
YTDL_COOKIES_ENABLED = if cfg.cookies.enable then "true" else "false";
|
|
||||||
YTDL_COOKIES_FILEPATH = cfg.cookies.file;
|
|
||||||
YTDL_COOKIES_FROMBROWSER_BROWSER = cfg.cookies.fromBrowser.browser;
|
|
||||||
YTDL_COOKIES_FROMBROWSER_KEYRING = cfg.cookies.fromBrowser.keyring;
|
|
||||||
YTDL_COOKIES_FROMBROWSER_PROFILE = cfg.cookies.fromBrowser.profile;
|
|
||||||
YTDL_COOKIES_FROMBROWSER_CONTAINER = cfg.cookies.fromBrowser.container;
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "simple";
|
|
||||||
User = cfg.user;
|
|
||||||
Group = cfg.group;
|
|
||||||
ExecStart = "${lib.getExe cfg.package} serve";
|
|
||||||
Restart = "on-failure";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d ${cfg.cacheDir} 0770 ${cfg.user} ${cfg.group} -"
|
|
||||||
];
|
|
||||||
|
|
||||||
networking.firewall = mkIf cfg.openFirewall {
|
|
||||||
allowedTCPPorts = [ cfg.port ];
|
|
||||||
};
|
|
||||||
|
|
||||||
users = {
|
|
||||||
users = mkIf (cfg.user == "ytdl-web") {
|
|
||||||
ytdl-web = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = cfg.group;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
groups = mkIf (cfg.group == "ytdl-web") {
|
|
||||||
ytdl-web = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
{ buildGoModule
|
|
||||||
, installShellFiles
|
|
||||||
, lib
|
|
||||||
, rev
|
|
||||||
, version
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
buildGoModule rec {
|
|
||||||
pname = "ytdl-web";
|
|
||||||
inherit version;
|
|
||||||
|
|
||||||
src = ./..;
|
|
||||||
|
|
||||||
vendorHash = "sha256-Rqh5tGcSey53e0Ln3u5agvOwRJ6/I1eUpzRylwtjhQo=";
|
|
||||||
|
|
||||||
ldflags = [
|
|
||||||
"-s"
|
|
||||||
"-w"
|
|
||||||
"-X $VERSION_PKG.Version=${version}"
|
|
||||||
"-X $VERSION_PKG.Build=${rev}"
|
|
||||||
"-X $VERSION_PKG.BuildDate=1970-01-01T0:00:00+0000"
|
|
||||||
"-X $VERSION_PKG.BuiltBy=nix"
|
|
||||||
];
|
|
||||||
|
|
||||||
nativeBuildInputs = [ installShellFiles ];
|
|
||||||
|
|
||||||
postInstall = ''
|
|
||||||
installShellCompletion --cmd ${pname} \
|
|
||||||
--zsh <($out/bin/${pname} completion zsh) \
|
|
||||||
--bash <($out/bin/${pname} completion bash) \
|
|
||||||
--fish <($out/bin/${pname} completion fish)
|
|
||||||
'';
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "Yet another yt-dlp web frontend written in Go.";
|
|
||||||
homepage = "https://git.fifitido.net/apps/ytdl-web";
|
|
||||||
license = licenses.gpl3Only;
|
|
||||||
mainProgram = "ytdl-web";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package ytdl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Exec(binary, url string, options ...Option) error {
|
||||||
|
opts := Options{
|
||||||
|
args: []string{url},
|
||||||
|
stdin: nil,
|
||||||
|
stdout: nil,
|
||||||
|
stderr: nil,
|
||||||
|
output: nil,
|
||||||
|
}
|
||||||
|
for _, opt := range options {
|
||||||
|
if err := opt(&opts); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(binary, opts.args...)
|
||||||
|
|
||||||
|
if opts.stdin != nil {
|
||||||
|
cmd.Stdin = opts.stdin
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.stdout != nil {
|
||||||
|
cmd.Stdout = opts.stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.stderr != nil {
|
||||||
|
cmd.Stderr = opts.stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, bufOk := opts.stdout.(*bytes.Buffer)
|
||||||
|
meta, metaOk := opts.output.(*metadata.Metadata)
|
||||||
|
if bufOk && metaOk {
|
||||||
|
if err := json.Unmarshal(buf.Bytes(), meta); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
package ytdl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"go.fifitido.net/ytdl-web/pkg/utils"
|
||||||
|
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||||
|
"golang.org/x/exp/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
args []string
|
||||||
|
stdin io.Reader
|
||||||
|
stdout io.Writer
|
||||||
|
stderr io.Writer
|
||||||
|
output interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*Options) error
|
||||||
|
|
||||||
|
func WithFormat(format string) Option {
|
||||||
|
return func(opts *Options) error {
|
||||||
|
opts.args = append(opts.args, "--format", format)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithCookieFile(cookieFile string) Option {
|
||||||
|
return func(opts *Options) error {
|
||||||
|
opts.args = append(opts.args, "--cookies", cookieFile)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithDumpJson(meta *metadata.Metadata) Option {
|
||||||
|
return func(opts *Options) error {
|
||||||
|
opts.args = append(opts.args, "--dump-single-json")
|
||||||
|
opts.stdout = new(bytes.Buffer)
|
||||||
|
opts.output = meta
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLoadJson(metadata *metadata.Metadata) Option {
|
||||||
|
return func(opts *Options) error {
|
||||||
|
opts.args = append(opts.args, "--load-info-json", "-")
|
||||||
|
|
||||||
|
json, err := json.Marshal(metadata)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.stdin = bytes.NewBuffer(json)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithBrowserCookies(browser, keyring, profile, container string) Option {
|
||||||
|
return func(opts *Options) error {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString(browser)
|
||||||
|
|
||||||
|
if keyring != "" {
|
||||||
|
sb.WriteByte('+')
|
||||||
|
sb.WriteString(keyring)
|
||||||
|
}
|
||||||
|
|
||||||
|
if profile != "" {
|
||||||
|
sb.WriteByte(':')
|
||||||
|
sb.WriteString(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if container != "" {
|
||||||
|
sb.WriteByte(':')
|
||||||
|
sb.WriteByte(':')
|
||||||
|
sb.WriteString(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.args = append(opts.args, "--cookies-from-browser", sb.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithStreamOutput(output io.Writer) Option {
|
||||||
|
return func(opts *Options) error {
|
||||||
|
opts.args = append(opts.args, "--output", "-")
|
||||||
|
opts.stdout = output
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithDebug() Option {
|
||||||
|
return func(opts *Options) error {
|
||||||
|
opts.stdout = utils.LoggerWriter(slog.With("module", "ytdl"), slog.LevelDebug)
|
||||||
|
opts.stderr = utils.LoggerWriter(slog.With("module", "ytdl"), slog.LevelDebug)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithPlaylistIndex(index int) Option {
|
||||||
|
return func(opts *Options) error {
|
||||||
|
opts.args = append(opts.args, "--playlist-items", fmt.Sprint(index+1))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package ytdl
|
|
||||||
|
|
||||||
type Error struct {
|
|
||||||
stdout string
|
|
||||||
stderr string
|
|
||||||
child error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
|
||||||
return e.child.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Stdout() string {
|
|
||||||
return e.stdout
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Stderr() string {
|
|
||||||
return e.stderr
|
|
||||||
}
|
|
103
pkg/ytdl/ytdl.go
103
pkg/ytdl/ytdl.go
|
@ -2,8 +2,6 @@ package ytdl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -29,7 +27,7 @@ type ytdlImpl struct {
|
||||||
|
|
||||||
func NewYtdl(cfg *config.Config, logger *slog.Logger, cache cache.MetadataCache) Ytdl {
|
func NewYtdl(cfg *config.Config, logger *slog.Logger, cache cache.MetadataCache) Ytdl {
|
||||||
cmd := exec.Command(
|
cmd := exec.Command(
|
||||||
cfg.Ytdlp.BinaryPath,
|
cfg.BinaryPath,
|
||||||
"--version",
|
"--version",
|
||||||
)
|
)
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
|
@ -44,44 +42,32 @@ func NewYtdl(cfg *config.Config, logger *slog.Logger, cache cache.MetadataCache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildBrowserCookieString(browser, keyring, profile, container string) string {
|
func (y *ytdlImpl) baseOptions(url string) []Option {
|
||||||
var sb strings.Builder
|
options := []Option{}
|
||||||
sb.WriteString(browser)
|
|
||||||
|
|
||||||
if keyring != "" {
|
metadata, err := y.cache.Get(url)
|
||||||
sb.WriteByte('+')
|
if err == nil {
|
||||||
sb.WriteString(keyring)
|
options = append(options, WithLoadJson(metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
if profile != "" {
|
|
||||||
sb.WriteByte(':')
|
|
||||||
sb.WriteString(profile)
|
|
||||||
}
|
|
||||||
|
|
||||||
if container != "" {
|
|
||||||
sb.WriteByte(':')
|
|
||||||
sb.WriteByte(':')
|
|
||||||
sb.WriteString(container)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (y *ytdlImpl) appendCookieArgs(args []string) []string {
|
|
||||||
if y.cfg.Cookies.Enabled {
|
if y.cfg.Cookies.Enabled {
|
||||||
if y.cfg.Cookies.FromBrowser.Browser != "" {
|
if y.cfg.Cookies.FromBrowser.Browser != "" {
|
||||||
args = append(args, "--cookies-from-browser", buildBrowserCookieString(
|
options = append(options, WithBrowserCookies(
|
||||||
y.cfg.Cookies.FromBrowser.Browser,
|
y.cfg.Cookies.FromBrowser.Browser,
|
||||||
y.cfg.Cookies.FromBrowser.Keyring,
|
y.cfg.Cookies.FromBrowser.Keyring,
|
||||||
y.cfg.Cookies.FromBrowser.Profile,
|
y.cfg.Cookies.FromBrowser.Profile,
|
||||||
y.cfg.Cookies.FromBrowser.Container,
|
y.cfg.Cookies.FromBrowser.Container,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
args = append(args, "--cookies", y.cfg.Cookies.FilePath)
|
options = append(options, WithCookieFile(y.cfg.Cookies.FilePath))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return args
|
if y.cfg.IsDevelopment() {
|
||||||
|
options = append(options, WithDebug())
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *ytdlImpl) Version() string {
|
func (y *ytdlImpl) Version() string {
|
||||||
|
@ -95,29 +81,14 @@ func (y *ytdlImpl) GetMetadata(url string) (*metadata.Metadata, error) {
|
||||||
return meta, nil
|
return meta, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
args := []string{
|
|
||||||
url,
|
|
||||||
"--dump-single-json",
|
|
||||||
}
|
|
||||||
|
|
||||||
args = y.appendCookieArgs(args)
|
|
||||||
|
|
||||||
cmd := exec.Command(y.cfg.Ytdlp.BinaryPath, args...)
|
|
||||||
|
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
attrs := []any{
|
|
||||||
slog.String("url", url),
|
|
||||||
slog.String("error", err.Error()),
|
|
||||||
}
|
|
||||||
|
|
||||||
y.logger.Error("failed to get metadata", attrs...)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
meta = &metadata.Metadata{}
|
meta = &metadata.Metadata{}
|
||||||
if err := json.Unmarshal(out, meta); err != nil {
|
options := append(
|
||||||
y.logger.Error("failed to unmarshal metadata", slog.String("url", url), slog.String("error", err.Error()))
|
y.baseOptions(url),
|
||||||
|
WithDumpJson(meta),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := Exec(y.cfg.BinaryPath, url, options...); err != nil {
|
||||||
|
y.logger.Error("failed to get metadata", slog.String("url", url), slog.String("error", err.Error()))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,37 +101,17 @@ func (y *ytdlImpl) GetMetadata(url string) (*metadata.Metadata, error) {
|
||||||
|
|
||||||
// Download implements Ytdl
|
// Download implements Ytdl
|
||||||
func (y *ytdlImpl) Download(w io.Writer, url, format string, index int) error {
|
func (y *ytdlImpl) Download(w io.Writer, url, format string, index int) error {
|
||||||
args := []string{
|
options := append(
|
||||||
url,
|
y.baseOptions(url),
|
||||||
"--format", format,
|
WithFormat(format),
|
||||||
"--output", "-",
|
WithStreamOutput(w),
|
||||||
}
|
)
|
||||||
|
|
||||||
if index >= 0 {
|
if index >= 0 {
|
||||||
args = append(args, "--playlist-ites", fmt.Sprint(index+1))
|
options = append(options, WithPlaylistIndex(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
args = y.appendCookieArgs(args)
|
if err := Exec(y.cfg.BinaryPath, url, options...); err != nil {
|
||||||
|
|
||||||
metadata, err := y.cache.Get(url)
|
|
||||||
if err == nil {
|
|
||||||
args = append(args, "--load-info-json", "-")
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command(y.cfg.Ytdlp.BinaryPath, args...)
|
|
||||||
cmd.Stdout = w
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
json, err := json.Marshal(metadata)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Stdin = bytes.NewReader(json)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
y.logger.Error("failed to download", slog.String("url", url), slog.String("error", err.Error()))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue