Files
ytdlp-site/main.go

182 lines
4.8 KiB
Go

package main
import (
"fmt"
"html/template"
"io"
golog "log"
"os"
"path/filepath"
"time"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"ytdlp-site/config"
"ytdlp-site/database"
"ytdlp-site/ffmpeg"
"ytdlp-site/handlers"
"ytdlp-site/media"
"ytdlp-site/originals"
"ytdlp-site/playlists"
"ytdlp-site/transcodes"
"ytdlp-site/users"
"ytdlp-site/ytdlp"
)
var db *gorm.DB
func ensureAdminAccount(db *gorm.DB) error {
var user users.User
if err := db.Where("username = ?", "admin").First(&user).Error; err != nil {
// no such user
password, err := config.GetAdminInitialPassword()
if err != nil {
return err
}
err = users.Create(db, "admin", password)
if err != nil {
return err
}
}
return nil
}
func main() {
initLogger()
log.Infof("GitSHA: %s", config.GetGitSHA())
log.Infof("BuildDate: %s", config.GetBuildDate())
ffmpeg.Init(log)
handlers.Init(log)
ytdlp.Init(log)
originals.Init(log)
defer originals.Fini()
gormLogger := logger.New(
golog.New(os.Stdout, "\r\n", golog.LstdFlags), // io writer
logger.Config{
SlowThreshold: time.Second, // Slow SQL threshold
LogLevel: logger.Warn, // Log level
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
ParameterizedQueries: true, // Don't include params in the SQL log
Colorful: false, // Disable color
},
)
// Create config database
err := os.MkdirAll(config.GetConfigDir(), 0700)
if err != nil {
log.Panicf("failed to create config dir %s", config.GetConfigDir())
}
// Initialize database
dbPath := filepath.Join(config.GetConfigDir(), "videos.db")
db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
Logger: gormLogger,
})
if err != nil {
log.Panicf("failed to connect to database %s", dbPath)
}
// set only a single connection so we don't actually have concurrent writes
sqlDB, err := db.DB()
if err != nil {
log.Panicln("failed to retrieve database")
}
sqlDB.SetMaxOpenConns(1)
// Migrate the schema
db.AutoMigrate(&originals.Original{}, &playlists.Playlist{},
&media.Video{}, &media.Audio{}, &media.VideoClip{},
&users.User{}, &TempURL{}, &transcodes.Transcode{})
database.Init(db, log)
defer database.Fini()
err = handlers.Init(log)
if err != nil {
panic(fmt.Sprintf("%v", err))
}
defer handlers.Fini()
go PeriodicCleanup()
// create a user
err = ensureAdminAccount(db)
if err != nil {
panic(fmt.Sprintf("failed to create admin user: %v", err))
}
// Initialize Echo
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Templates
t := &Template{
templates: template.Must(template.ParseGlob("templates/*.html")),
}
e.Renderer = t
// Routes
e.GET("/", homeHandler)
e.GET("/login", handlers.LoginGet)
e.POST("/login", handlers.LoginPost)
// e.GET("/register", registerHandler)
// e.POST("/register", registerPostHandler)
e.GET("/logout", handlers.LogoutGet)
e.GET("/download", downloadHandler, handlers.AuthMiddleware)
e.POST("/download", downloadPostHandler, handlers.AuthMiddleware)
e.GET("/videos", videosHandler, handlers.AuthMiddleware)
e.GET("/video/:id", videoHandler, handlers.AuthMiddleware)
e.POST("/video/:id/restart", videoRestartHandler, handlers.AuthMiddleware)
e.POST("/video/:id/delete", deleteOriginalHandler, handlers.AuthMiddleware)
e.GET("/temp/:token", tempHandler)
e.POST("/video/:id/process", processHandler, handlers.AuthMiddleware)
e.POST("/video/:id/toggle_watched", handlers.ToggleWatched, handlers.AuthMiddleware)
e.POST("/video/:id/set_timestamp", handlers.SetTimestamp, handlers.AuthMiddleware)
e.POST("/delete_video/:id", deleteVideoHandler, handlers.AuthMiddleware)
e.POST("/delete_audio/:id", deleteAudioHandler, handlers.AuthMiddleware)
e.POST("/transcode_to_video/:id", transcodeToVideoHandler, handlers.AuthMiddleware)
e.POST("/transcode_to_audio/:id", transcodeToAudioHandler, handlers.AuthMiddleware)
e.GET("/status", handlers.StatusGet, handlers.AuthMiddleware)
e.GET("/videos/events", handlers.VideosEvents, handlers.AuthMiddleware)
e.GET("/p/:id", playlistHandler, handlers.AuthMiddleware)
e.POST("/p/:id/delete", deletePlaylistHandler, handlers.AuthMiddleware)
dataGroup := e.Group("/data")
dataGroup.Use(handlers.AuthMiddleware)
dataGroup.Static("/", config.GetDataDir())
staticGroup := e.Group("/static")
staticGroup.Use(handlers.AuthMiddleware)
staticGroup.Static("/", "static")
// tidy up the transcodes database
log.Debug("tidy transcodes database...")
cleanupTranscodes()
// Start server
e.Logger.Fatal(e.Start(":8080"))
}
// Template renderer
type Template struct {
templates *template.Template
}
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
return t.templates.ExecuteTemplate(w, name, data)
}