basic status page, move config into data dir

This commit is contained in:
Carl Pearson
2024-10-17 05:44:41 -06:00
parent 57ba3767d1
commit 38689752bd
11 changed files with 130 additions and 65 deletions

View File

@@ -1,5 +1,4 @@
data
config
go.sum
*.mp4
*.m4a

1
.gitignore vendored
View File

@@ -1,4 +1,3 @@
config
go.sum
*.mp4
*.m4a

View File

@@ -7,6 +7,7 @@ RUN wget -q -d https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_
&& chmod +x /usr/local/bin/yt-dlp
ADD *.go /src/.
ADD config /src/config
ADD database /src/database
Add ffmpeg /src/ffmpeg
ADD handlers /src/handlers

View File

@@ -8,7 +8,7 @@ go mod tidy
export YTDLP_SITE_ADMIN_INITIAL_PASSWORD=abc123
export YTDLP_SITE_SESSION_AUTH_KEY=v9qpt37hc4qpmhf
go run \
-ldflags "-X main.GitSHA=$(git rev-parse HEAD) -X main.BuildDate=$(date +%Y-%m-%d)" \
-ldflags "-X ytdlp-site/config.gitSHA=$(git rev-parse HEAD) -X ytdlp-site/config.buildDate=$(date +%Y-%m-%d)" \
*.go
```

View File

@@ -1,15 +1,16 @@
package main
package config
import (
"fmt"
"os"
"path/filepath"
"strings"
)
var GitSHA string
var BuildDate string
var gitSHA string
var buildDate string
func getDataDir() string {
func GetDataDir() string {
value, exists := os.LookupEnv("YTDLP_SITE_DATA_DIR")
if exists {
return value
@@ -17,15 +18,11 @@ func getDataDir() string {
return "data"
}
func getConfigDir() string {
value, exists := os.LookupEnv("YTDLP_SITE_CONFIG_DIR")
if exists {
return value
}
return "config"
func GetConfigDir() string {
return filepath.Join(GetDataDir(), "config")
}
func getAdminInitialPassword() (string, error) {
func GetAdminInitialPassword() (string, error) {
key := "YTDLP_SITE_ADMIN_INITIAL_PASSWORD"
value, exists := os.LookupEnv(key)
if exists {
@@ -34,7 +31,7 @@ func getAdminInitialPassword() (string, error) {
return "", fmt.Errorf("please set %s", key)
}
func getSessionAuthKey() ([]byte, error) {
func GetSessionAuthKey() ([]byte, error) {
key := "YTDLP_SITE_SESSION_AUTH_KEY"
value, exists := os.LookupEnv(key)
if exists {
@@ -43,7 +40,7 @@ func getSessionAuthKey() ([]byte, error) {
return []byte{}, fmt.Errorf("please set %s", key)
}
func getSecure() bool {
func GetSecure() bool {
key := "YTDLP_SITE_SECURE"
if value, exists := os.LookupEnv(key); exists {
lower := strings.ToLower(value)
@@ -54,18 +51,18 @@ func getSecure() bool {
return false
}
func getGitSHA() string {
if GitSHA == "" {
func GetGitSHA() string {
if gitSHA == "" {
return "<not provided>"
} else {
return GitSHA
return gitSHA
}
}
func getBuildDate() string {
if BuildDate == "" {
func GetBuildDate() string {
if buildDate == "" {
return "<not provided>"
} else {
return BuildDate
return buildDate
}
}

View File

@@ -16,27 +16,15 @@ import (
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"ytdlp-site/config"
"ytdlp-site/ffmpeg"
"ytdlp-site/handlers"
"ytdlp-site/media"
"ytdlp-site/originals"
"ytdlp-site/playlists"
"ytdlp-site/ytdlp"
)
type Footer struct {
BuildDate string
BuildId string
BuildIdShort string
}
func makeFooter() Footer {
return Footer{
BuildDate: getBuildDate(),
BuildId: getGitSHA(),
BuildIdShort: getGitSHA()[0:7],
}
}
var ytdlpAudioOptions = []string{"-f", "bestvideo[height<=1080]+bestaudio/best[height<=1080]"}
var ytdlpVideoOptions = []string{"-f", "bestaudio"}
@@ -71,7 +59,7 @@ func homeHandler(c echo.Context) error {
return c.Render(http.StatusOK, "home.html",
map[string]interface{}{
"Footer": makeFooter(),
"Footer": handlers.MakeFooter(),
})
}
@@ -123,7 +111,7 @@ func logoutHandler(c echo.Context) error {
func downloadHandler(c echo.Context) error {
return c.Render(http.StatusOK, "download.html",
map[string]interface{}{
"Footer": makeFooter(),
"Footer": handlers.MakeFooter(),
})
}
@@ -518,7 +506,7 @@ func processOriginal(originalID uint) {
if hasOriginalVideo {
videoFilepath := filepath.Join(getDataDir(), video.Filename)
videoFilepath := filepath.Join(config.GetDataDir(), video.Filename)
_, err := os.Stat(videoFilepath)
if os.IsNotExist(err) {
fmt.Println("Skipping non-existant file for processOriginal")
@@ -540,7 +528,7 @@ func processOriginal(originalID uint) {
} else if hasOriginalAudio {
audioFilepath := filepath.Join(getDataDir(), audio.Filename)
audioFilepath := filepath.Join(config.GetDataDir(), audio.Filename)
_, err := os.Stat(audioFilepath)
if os.IsNotExist(err) {
fmt.Println("Skipping non-existant audio file for processOriginal")
@@ -591,7 +579,7 @@ func startDownload(originalID uint, videoURL string, audioOnly bool) {
// create temporary directory
// do this in the data directory since /tmp is sometimes a different filesystem
tempDir, err := os.MkdirTemp(getDataDir(), "dl")
tempDir, err := os.MkdirTemp(config.GetDataDir(), "dl")
if err != nil {
log.Errorln("Error creating temporary directory:", err)
originals.SetStatus(db, originalID, originals.StatusFailed)
@@ -641,7 +629,7 @@ func startDownload(originalID uint, videoURL string, audioOnly bool) {
// move to data directory
srcPath := filepath.Join(tempDir, dlFilename)
dlFilepath := filepath.Join(getDataDir(), dlFilename)
dlFilepath := filepath.Join(config.GetDataDir(), dlFilename)
log.Debugln("rename", srcPath, "->", dlFilepath)
err = os.Rename(srcPath, dlFilepath)
if err != nil {
@@ -751,7 +739,7 @@ func videosHandler(c echo.Context) error {
map[string]interface{}{
"videos": origs,
"playlists": playlists,
"Footer": makeFooter(),
"Footer": handlers.MakeFooter(),
})
}
@@ -831,7 +819,7 @@ func videoHandler(c echo.Context) error {
Order("CASE WHEN source = 'original' THEN 1 ELSE 0 END, bps ASC").
Find(&audios)
dataDir := getDataDir()
dataDir := config.GetDataDir()
// create temporary URLs
var videoURLs []VideoTemplate
@@ -884,7 +872,7 @@ func videoHandler(c echo.Context) error {
"videos": videoURLs,
"audios": audioURLs,
"dataDir": dataDir,
"Footer": makeFooter(),
"Footer": handlers.MakeFooter(),
})
}
@@ -917,7 +905,7 @@ func deleteTranscodedVideos(originalID uint) {
var videos []media.Video
db.Where("original_id = ?", originalID).Where("source = ?", "transcode").Find(&videos)
for _, video := range videos {
path := filepath.Join(getDataDir(), video.Filename)
path := filepath.Join(config.GetDataDir(), video.Filename)
log.Debugln("remove video", path)
err := os.Remove(path)
if err != nil {
@@ -931,7 +919,7 @@ func deleteOriginalVideos(originalID uint) {
var videos []media.Video
db.Where("original_id = ?", originalID).Where("source = ?", "original").Find(&videos)
for _, video := range videos {
path := filepath.Join(getDataDir(), video.Filename)
path := filepath.Join(config.GetDataDir(), video.Filename)
fmt.Println("remove", path)
err := os.Remove(path)
if err != nil {
@@ -945,7 +933,7 @@ func deleteAudiosWithSource(originalID uint, source string) {
var audios []media.Audio
db.Where("original_id = ?", originalID).Where("source = ?", source).Find(&audios)
for _, audio := range audios {
path := filepath.Join(getDataDir(), audio.Filename)
path := filepath.Join(config.GetDataDir(), audio.Filename)
log.Debugln("remove audio", path)
err := os.Remove(path)
if err != nil {
@@ -987,7 +975,7 @@ func deleteVideo(id int) error {
return result.Error
}
videoPath := filepath.Join(getDataDir(), video.Filename)
videoPath := filepath.Join(config.GetDataDir(), video.Filename)
log.Debugln("remove", videoPath)
err := os.Remove(videoPath)
if err != nil {
@@ -1030,7 +1018,7 @@ func deleteAudioHandler(c echo.Context) error {
return c.Redirect(http.StatusSeeOther, referrer)
}
filePath := filepath.Join(getDataDir(), audio.Filename)
filePath := filepath.Join(config.GetDataDir(), audio.Filename)
log.Debugln("remove", filePath)
err := os.Remove(filePath)
if err != nil {
@@ -1157,7 +1145,7 @@ func playlistHandler(c echo.Context) error {
"playlist": playlist,
"unwatched": origs,
"watched": watchedOrigs,
"Footer": makeFooter(),
"Footer": handlers.MakeFooter(),
})
}

17
handlers/footer.go Normal file
View File

@@ -0,0 +1,17 @@
package handlers
import "ytdlp-site/config"
type Footer struct {
BuildDate string
BuildId string
BuildIdShort string
}
func MakeFooter() Footer {
return Footer{
BuildDate: config.GetBuildDate(),
BuildId: config.GetGitSHA(),
BuildIdShort: config.GetGitSHA()[0:7],
}
}

28
handlers/status.go Normal file
View File

@@ -0,0 +1,28 @@
package handlers
import (
"net/http"
"github.com/labstack/echo/v4"
"ytdlp-site/ffmpeg"
"ytdlp-site/ytdlp"
)
func StatusGet(c echo.Context) error {
ytdlpStdout, _, err := ytdlp.Run("--version")
if err != nil {
log.Errorln(err)
}
ffmpegStdout, _, err := ffmpeg.Ffmpeg("-version")
if err != nil {
log.Errorln(err)
}
return c.Render(http.StatusOK, "status.html", map[string]interface{}{
"ytdlp": string(ytdlpStdout),
"ffmpeg": string(ffmpegStdout),
"Footer": MakeFooter(),
})
}

20
main.go
View File

@@ -16,6 +16,7 @@ import (
"gorm.io/gorm"
"gorm.io/gorm/logger"
"ytdlp-site/config"
"ytdlp-site/database"
"ytdlp-site/ffmpeg"
"ytdlp-site/handlers"
@@ -33,7 +34,7 @@ func ensureAdminAccount(db *gorm.DB) error {
if err := db.Where("username = ?", "admin").First(&user).Error; err != nil {
// no such user
password, err := getAdminInitialPassword()
password, err := config.GetAdminInitialPassword()
if err != nil {
return err
}
@@ -50,8 +51,8 @@ func main() {
initLogger()
log.Infof("GitSHA: %s", getGitSHA())
log.Infof("BuildDate: %s", getBuildDate())
log.Infof("GitSHA: %s", config.GetGitSHA())
log.Infof("BuildDate: %s", config.GetBuildDate())
ffmpeg.Init(log)
handlers.Init(log)
@@ -69,13 +70,13 @@ func main() {
)
// Create config database
err := os.MkdirAll(getConfigDir(), 0700)
err := os.MkdirAll(config.GetConfigDir(), 0700)
if err != nil {
log.Panicf("failed to create config dir %s", getConfigDir())
log.Panicf("failed to create config dir %s", config.GetConfigDir())
}
// Initialize database
dbPath := filepath.Join(getConfigDir(), "videos.db")
dbPath := filepath.Join(config.GetConfigDir(), "videos.db")
db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
Logger: gormLogger,
})
@@ -106,7 +107,7 @@ func main() {
}
// create the cookie store
key, err := getSessionAuthKey()
key, err := config.GetSessionAuthKey()
if err != nil {
panic(fmt.Sprintf("%v", err))
}
@@ -145,19 +146,20 @@ func main() {
e.POST("/delete_audio/:id", deleteAudioHandler, authMiddleware)
e.POST("/transcode_to_video/:id", transcodeToVideoHandler, authMiddleware)
e.POST("/transcode_to_audio/:id", transcodeToAudioHandler, authMiddleware)
e.GET("/status", handlers.StatusGet, authMiddleware)
e.GET("/p/:id", playlistHandler, authMiddleware)
e.POST("/p/:id/delete", deletePlaylistHandler, authMiddleware)
dataGroup := e.Group("/data")
dataGroup.Use(authMiddleware)
dataGroup.Static("/", getDataDir())
dataGroup.Static("/", config.GetDataDir())
staticGroup := e.Group("/static")
staticGroup.Use(authMiddleware)
staticGroup.Static("/", "static")
secure := getSecure()
secure := config.GetSecure()
store.Options = &sessions.Options{
Path: "/",

33
templates/status.html Normal file
View File

@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.original.Title}}</title>
<link rel="stylesheet" href="/static/style/common.css">
<link rel="stylesheet" href="/static/style/video.css">
<link rel="stylesheet" href="/static/style/status.css">
{{template "header-css" .}}
{{template "footer-css" .}}
</head>
<body>
{{template "header" .}}
<h1>Status</h1>
<div class="ytdlp">
<h2>yt-dlp</h2>
<div class="raw">
{{.ytdlp}}
</div>
</div>
<div class="ffmpeg">
<h2>ffmpeg</h2>
<div class="raw">
{{.ffmpeg}}
</div>
</div>
{{template "footer" .}}
</body>
</html>

View File

@@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"time"
"ytdlp-site/config"
"ytdlp-site/ffmpeg"
"ytdlp-site/media"
"ytdlp-site/originals"
@@ -24,7 +25,7 @@ func videoToVideo(transID uint, height uint, fps float64, srcFilepath string) {
// determine destination path
dstFilename := uuid.Must(uuid.NewV7()).String()
dstFilename = fmt.Sprintf("%s.mp4", dstFilename)
dstFilepath := filepath.Join(getDataDir(), dstFilename)
dstFilepath := filepath.Join(config.GetDataDir(), dstFilename)
err := ensureDirFor(dstFilepath)
if err != nil {
@@ -100,7 +101,7 @@ func videoToAudio(transID uint, kbps uint, videoFilepath string) {
// determine destination path
audioFilename := uuid.Must(uuid.NewV7()).String()
audioFilename = fmt.Sprintf("%s.mp3", audioFilename)
audioFilepath := filepath.Join(getDataDir(), audioFilename)
audioFilepath := filepath.Join(config.GetDataDir(), audioFilename)
// ensure destination directory
err := ensureDirFor(audioFilepath)
@@ -154,7 +155,7 @@ func audioToAudio(transID uint, kbps uint, srcFilepath string) {
// determine destination path
dstFilename := uuid.Must(uuid.NewV7()).String()
dstFilename = fmt.Sprintf("%s.mp3", dstFilename)
dstFilepath := filepath.Join(getDataDir(), dstFilename)
dstFilepath := filepath.Join(config.GetDataDir(), dstFilename)
// ensure destination directory
err := ensureDirFor(dstFilepath)
@@ -261,7 +262,7 @@ func transcodePending() {
db.Delete(&trans)
continue
}
srcFilepath := filepath.Join(getDataDir(), srcVideo.Filename)
srcFilepath := filepath.Join(config.GetDataDir(), srcVideo.Filename)
if trans.DstKind == "video" {
videoToVideo(trans.ID, trans.Height, trans.FPS, srcFilepath)
@@ -280,7 +281,7 @@ func transcodePending() {
db.Delete(&trans)
continue
}
srcFilepath := filepath.Join(getDataDir(), srcAudio.Filename)
srcFilepath := filepath.Join(config.GetDataDir(), srcAudio.Filename)
audioToAudio(trans.ID, trans.Rate, srcFilepath)
} else {
fmt.Println("unexpected src kind for Transcode", trans)