basic status page, move config into data dir
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
data
|
||||
config
|
||||
go.sum
|
||||
*.mp4
|
||||
*.m4a
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
config
|
||||
go.sum
|
||||
*.mp4
|
||||
*.m4a
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
```
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
46
handlers.go
46
handlers.go
@@ -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
17
handlers/footer.go
Normal 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
28
handlers/status.go
Normal 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
20
main.go
@@ -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
33
templates/status.html
Normal 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>
|
11
workers.go
11
workers.go
@@ -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)
|
||||
|
Reference in New Issue
Block a user