Compare commits
22 Commits
7c69d73083
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| de798246b9 | |||
| 1b9fb93cf6 | |||
| 667f2a88ba | |||
| ee4be382b9 | |||
| 12137b1fa8 | |||
| 18d640ab1f | |||
| fab6ba9216 | |||
| 36d3505746 | |||
| 5551ad78b9 | |||
| 204decf1dc | |||
| f3d454988a | |||
| e2ac4ec983 | |||
| e1fd6fbeb7 | |||
| 61b7d4c2ca | |||
| 4b36be3819 | |||
| f668f59f70 | |||
| 91a9c69cba | |||
| 2b00bec445 | |||
| 54c6740dfe | |||
| 5ef8692a3a | |||
| e5e1987bd1 | |||
| ff3b2765a7 |
33
.build.yaml
33
.build.yaml
@@ -1,33 +0,0 @@
|
|||||||
image: debian/bookworm
|
|
||||||
|
|
||||||
secrets:
|
|
||||||
- a19cbc4c-b6a1-414e-bf1c-1e06abc684eb
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- print-env: |
|
|
||||||
echo "$JOB_ID"
|
|
||||||
echo "$JOB_URL"
|
|
||||||
echo "$BUILD_SUBMITTER"
|
|
||||||
echo "$BUILD_REASON"
|
|
||||||
echo "$GIT_REF"
|
|
||||||
- setup-env: |
|
|
||||||
sudo timedatectl set-timezone America/Denver
|
|
||||||
echo "SLUG=ghcr.io/cwpearson/ytdlp-site" >> ~/.buildenv
|
|
||||||
echo "DATE=$(date +"%Y%m%d_%H%M")" >> ~/.buildenv
|
|
||||||
- prerequisites: |
|
|
||||||
bash ytdlp-site/.ci/debian_setup_docker.sh
|
|
||||||
- build: |
|
|
||||||
cd ytdlp-site
|
|
||||||
docker build . --file Dockerfile --build-arg GIT_SHA=$(git rev-parse HEAD) --tag "$SLUG:$DATE" --tag "$SLUG:latest"
|
|
||||||
- deploy: |
|
|
||||||
if [ "$GIT_REF" != "refs/heads/master" ]; then exit 0; fi
|
|
||||||
set +x
|
|
||||||
cat ~/.ghcr_token | docker login ghcr.io -u cwpearson --password-stdin
|
|
||||||
set -x
|
|
||||||
docker push "$SLUG:latest"
|
|
||||||
docker push "$SLUG:$DATE"
|
|
||||||
|
|
||||||
triggers:
|
|
||||||
- action: email
|
|
||||||
condition: failure
|
|
||||||
to: Carl Pearson <srht@carlpearson.net>
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
# Add Docker's official GPG key:
|
# Add Docker's official GPG key:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y ca-certificates curl
|
sudo apt-get install -y ca-certificates curl
|
||||||
|
|||||||
19
.ci/ubuntu_setup_docker.sh
Normal file
19
.ci/ubuntu_setup_docker.sh
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# Add Docker's official GPG key:
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y ca-certificates curl
|
||||||
|
sudo install -m 0755 -d /etc/apt/keyrings
|
||||||
|
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||||
|
sudo chmod a+r /etc/apt/keyrings/docker.asc
|
||||||
|
|
||||||
|
# Add the repository to Apt sources:
|
||||||
|
echo \
|
||||||
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
|
||||||
|
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
|
||||||
|
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
sudo apt-get update
|
||||||
|
|
||||||
|
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
|
|
||||||
|
sudo usermod -aG docker $(whoami)
|
||||||
56
.gitea/workflows/build-deploy.yml
Normal file
56
.gitea/workflows/build-deploy.yml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: Build and Deploy ytdlp-site
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# Runs every 2 days at 2:30 AM UTC
|
||||||
|
- cron: '30 2 */2 * *'
|
||||||
|
env:
|
||||||
|
SLUG: git.carlpearson.net/cwpearson/ytdlp-site
|
||||||
|
TZ: America/Denver
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Print environment info
|
||||||
|
run: |
|
||||||
|
echo "Job ID: ${{ github.run_id }}"
|
||||||
|
echo "Job URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
|
echo "Build Submitter: ${{ github.actor }}"
|
||||||
|
echo "Build Reason: ${{ github.event_name }}"
|
||||||
|
echo "Git Ref: ${{ github.ref }}"
|
||||||
|
|
||||||
|
- name: Setup environment
|
||||||
|
run: |
|
||||||
|
echo "DATE=$(date +"%Y%m%d_%H%M")" >> $GITHUB_ENV
|
||||||
|
echo "GIT_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install docker
|
||||||
|
run: |
|
||||||
|
bash .ci/ubuntu_setup_docker.sh
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
run: |
|
||||||
|
docker build . \
|
||||||
|
--file Dockerfile \
|
||||||
|
--build-arg GIT_SHA=${{ env.GIT_SHA }} \
|
||||||
|
--tag ${{ env.SLUG }}:${{ env.DATE }} \
|
||||||
|
--tag ${{ env.SLUG }}:latest
|
||||||
|
|
||||||
|
- name: Deploy to Container Registry
|
||||||
|
if: gitea.ref == 'refs/heads/master' && (gitea.event_name == 'push' || gitea.event_name == 'schedule')
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.GIT_PASSWORD }}" | docker login git.carlpearson.net -u "${{ secrets.GIT_USERNAME }}" --password-stdin
|
||||||
|
docker push ${{ env.SLUG }}:latest
|
||||||
|
docker push ${{ env.SLUG }}:${{ env.DATE }}
|
||||||
20
Dockerfile
20
Dockerfile
@@ -1,11 +1,15 @@
|
|||||||
FROM golang:1.23.3-bookworm AS builder
|
FROM golang:1.25.1-trixie AS builder
|
||||||
ARG GIT_SHA="<not provided>"
|
ARG GIT_SHA="<not provided>"
|
||||||
|
|
||||||
|
# install yt-dlp
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends --no-install-suggests wget
|
RUN apt-get update && apt-get install -y --no-install-recommends --no-install-suggests wget
|
||||||
RUN wget -q -d https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux -O /usr/local/bin/yt-dlp \
|
RUN wget -q -d https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux -O /usr/local/bin/yt-dlp \
|
||||||
&& chmod +x /usr/local/bin/yt-dlp
|
&& chmod +x /usr/local/bin/yt-dlp
|
||||||
|
|
||||||
|
# install deno
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends --no-install-suggests curl unzip
|
||||||
|
RUN curl -fsSL https://deno.land/install.sh | sh
|
||||||
|
|
||||||
ADD *.go /src/.
|
ADD *.go /src/.
|
||||||
ADD config /src/config
|
ADD config /src/config
|
||||||
ADD database /src/database
|
ADD database /src/database
|
||||||
@@ -13,24 +17,30 @@ ADD ffmpeg /src/ffmpeg
|
|||||||
ADD handlers /src/handlers
|
ADD handlers /src/handlers
|
||||||
ADD media /src/media
|
ADD media /src/media
|
||||||
ADD originals /src/originals
|
ADD originals /src/originals
|
||||||
Add playlists /src/playlists
|
ADD playlists /src/playlists
|
||||||
ADD transcodes /src/transcodes
|
ADD transcodes /src/transcodes
|
||||||
ADD users /src/users
|
ADD users /src/users
|
||||||
Add ytdlp /src/ytdlp
|
ADD ytdlp /src/ytdlp
|
||||||
ADD go.mod /src/.
|
ADD go.mod /src/.
|
||||||
|
|
||||||
RUN cd /src && go mod tidy
|
RUN cd /src && go mod tidy
|
||||||
RUN cd /src && go build -ldflags "-X ytdlp-site/config.gitSHA=${GIT_SHA} -X ytdlp-site/config.buildDate=$(date +%Y-%m-%d)" -o server *.go
|
RUN cd /src && go build -ldflags "-X ytdlp-site/config.gitSHA=${GIT_SHA} -X ytdlp-site/config.buildDate=$(date +%Y-%m-%d)" -o server *.go
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
FROM debian:trixie-slim
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends --no-install-suggests \
|
&& apt-get install -y --no-install-recommends --no-install-suggests \
|
||||||
ffmpeg \
|
ffmpeg \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# copy yt-dlp
|
||||||
COPY --from=0 /usr/local/bin/yt-dlp /usr/local/bin/yt-dlp
|
COPY --from=0 /usr/local/bin/yt-dlp /usr/local/bin/yt-dlp
|
||||||
COPY --from=0 /src/server /opt/server
|
COPY --from=0 /src/server /opt/server
|
||||||
|
|
||||||
|
# copy deno
|
||||||
|
COPY --from=0 /root/.deno /root/.deno
|
||||||
|
ENV PATH="/root/.deno/bin:$PATH"
|
||||||
|
|
||||||
ADD templates /opt/templates
|
ADD templates /opt/templates
|
||||||
ADD static /opt/static
|
ADD static /opt/static
|
||||||
|
|
||||||
|
|||||||
6
go.mod
6
go.mod
@@ -1,8 +1,8 @@
|
|||||||
module ytdlp-site
|
module ytdlp-site
|
||||||
|
|
||||||
go 1.23
|
go 1.24
|
||||||
|
|
||||||
toolchain go1.23.0
|
toolchain go1.24.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
@@ -10,6 +10,7 @@ require (
|
|||||||
github.com/labstack/echo/v4 v4.10.2
|
github.com/labstack/echo/v4 v4.10.2
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
golang.org/x/crypto v0.9.0
|
golang.org/x/crypto v0.9.0
|
||||||
|
golang.org/x/sys v0.8.0
|
||||||
gorm.io/driver/sqlite v1.5.1
|
gorm.io/driver/sqlite v1.5.1
|
||||||
gorm.io/gorm v1.25.1
|
gorm.io/gorm v1.25.1
|
||||||
)
|
)
|
||||||
@@ -26,7 +27,6 @@ require (
|
|||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.9.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
20
handlers.go
20
handlers.go
@@ -22,7 +22,6 @@ import (
|
|||||||
"ytdlp-site/originals"
|
"ytdlp-site/originals"
|
||||||
"ytdlp-site/playlists"
|
"ytdlp-site/playlists"
|
||||||
"ytdlp-site/transcodes"
|
"ytdlp-site/transcodes"
|
||||||
"ytdlp-site/users"
|
|
||||||
"ytdlp-site/ytdlp"
|
"ytdlp-site/ytdlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,23 +35,6 @@ type DisplayVideoClip struct {
|
|||||||
Stop string
|
Stop string
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerHandler(c echo.Context) error {
|
|
||||||
return c.Render(http.StatusOK, "register.html", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func registerPostHandler(c echo.Context) error {
|
|
||||||
username := c.FormValue("username")
|
|
||||||
password := c.FormValue("password")
|
|
||||||
|
|
||||||
err := users.Create(db, username, password)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return c.String(http.StatusInternalServerError, "Error creating user")
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.Redirect(http.StatusSeeOther, "/login")
|
|
||||||
}
|
|
||||||
|
|
||||||
func homeHandler(c echo.Context) error {
|
func homeHandler(c echo.Context) error {
|
||||||
_, err := handlers.GetUser(c)
|
_, err := handlers.GetUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -623,7 +605,7 @@ func startDownload(originalID uint, videoURL string, audioOnly bool) {
|
|||||||
cmd.Dir = tempDir
|
cmd.Dir = tempDir
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln("yt-dlp failed")
|
log.Errorf("yt-dlp run error: %v")
|
||||||
originals.SetStatus(originalID, originals.StatusFailed)
|
originals.SetStatus(originalID, originals.StatusFailed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
16
main.go
16
main.go
@@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
golog "log"
|
golog "log"
|
||||||
@@ -95,24 +94,25 @@ func main() {
|
|||||||
sqlDB.SetMaxOpenConns(1)
|
sqlDB.SetMaxOpenConns(1)
|
||||||
|
|
||||||
// Migrate the schema
|
// Migrate the schema
|
||||||
db.AutoMigrate(&originals.Original{}, &playlists.Playlist{},
|
if err := db.AutoMigrate(&originals.Original{}, &playlists.Playlist{},
|
||||||
&media.Video{}, &media.Audio{}, &media.VideoClip{},
|
&media.Video{}, &media.Audio{}, &media.VideoClip{},
|
||||||
&users.User{}, &TempURL{}, &transcodes.Transcode{})
|
&users.User{}, &TempURL{}, &transcodes.Transcode{}); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
database.Init(db, log)
|
database.Init(db, log)
|
||||||
defer database.Fini()
|
defer database.Fini()
|
||||||
err = handlers.Init(log)
|
err = handlers.Init(log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("%v", err))
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer handlers.Fini()
|
defer handlers.Fini()
|
||||||
|
|
||||||
go PeriodicCleanup()
|
go PeriodicCleanup()
|
||||||
|
|
||||||
// create a user
|
// create a user
|
||||||
err = ensureAdminAccount(db)
|
if err = ensureAdminAccount(db); err != nil {
|
||||||
if err != nil {
|
log.Fatal("create admin account error:", err)
|
||||||
panic(fmt.Sprintf("failed to create admin user: %v", err))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Echo
|
// Initialize Echo
|
||||||
@@ -132,8 +132,6 @@ func main() {
|
|||||||
e.GET("/", homeHandler)
|
e.GET("/", homeHandler)
|
||||||
e.GET("/login", handlers.LoginGet)
|
e.GET("/login", handlers.LoginGet)
|
||||||
e.POST("/login", handlers.LoginPost)
|
e.POST("/login", handlers.LoginPost)
|
||||||
// e.GET("/register", registerHandler)
|
|
||||||
// e.POST("/register", registerPostHandler)
|
|
||||||
e.GET("/logout", handlers.LogoutGet)
|
e.GET("/logout", handlers.LogoutGet)
|
||||||
e.GET("/download", downloadHandler, handlers.AuthMiddleware)
|
e.GET("/download", downloadHandler, handlers.AuthMiddleware)
|
||||||
e.POST("/download", downloadPostHandler, handlers.AuthMiddleware)
|
e.POST("/download", downloadPostHandler, handlers.AuthMiddleware)
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ func cleanupTranscodes() {
|
|||||||
err := db.Where("status = ?", "pending").
|
err := db.Where("status = ?", "pending").
|
||||||
Order("CASE " +
|
Order("CASE " +
|
||||||
"WHEN dst_kind = 'video' AND height = 540 THEN 0 " +
|
"WHEN dst_kind = 'video' AND height = 540 THEN 0 " +
|
||||||
"WHEN dst_kind = 'audio' AND rate = 96 THEN 0 " +
|
"WHEN dst_kind = 'audio' AND kbps = 96 THEN 0 " +
|
||||||
"ELSE 1 END").First(&trans).Error
|
"ELSE 1 END").First(&trans).Error
|
||||||
// err := db.First(&trans, "status = ?", "pending").Error
|
// err := db.First(&trans, "status = ?", "pending").Error
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
|||||||
Reference in New Issue
Block a user