videopage/main.go

196 lines
5.2 KiB
Go

package main
import (
"bufio"
"bytes"
"crypto/md5"
"embed"
"encoding/json"
"flag"
"fmt"
"html/template"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path"
"strings"
)
var (
templates *template.Template
//go:embed templates
fs embed.FS
config *Config
)
func main() {
var configPath string
var rescan bool
flag.StringVar(&configPath, "config", "config.yaml", "Path to the configuration file")
flag.BoolVar(&rescan, "rescan", false, "Rescan the data direcory")
flag.Parse()
var err error
config, err = NewConfigParseFile(configPath)
if err != nil {
log.Fatal(err.Error())
}
if rescan {
rescanFiles()
return
}
{
entry, err := os.Stat(path.Join(config.DataDirectory, "tmp"))
if os.IsNotExist(err) {
err = os.Mkdir(path.Join(config.DataDirectory, "tmp"), os.ModeDir)
if err != nil {
log.Printf("FATAL: can't create tmp directory: %s", err.Error())
os.Exit(-1)
}
}
if err != nil {
log.Printf("FATAL: can't stat tmp directory: %s", err.Error())
os.Exit(-2)
}
if !entry.IsDir() {
log.Printf("FATAL: tmp path isn't directory")
os.Exit(-3)
}
}
templates = template.Must(template.ParseFS(fs, "templates/*"))
log.Printf("Loaded templates: %s", templates.DefinedTemplates())
videoFS := http.FileServer(http.Dir(config.DataDirectory))
adminMux := NewAdminApi()
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
mux.HandleFunc("/video/index.json", videoIndexHandler)
mux.Handle("/video/", videoFS)
mux.Handle("/admin/", http.StripPrefix("/admin", adminMux))
if len(config.ApplicationPrefix) > 0 {
http.ListenAndServe(config.ListenAddress, http.StripPrefix(config.ApplicationPrefix, NewLogger(mux)))
} else {
http.ListenAndServe(config.ListenAddress, NewLogger(mux))
}
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
var v struct {
ApplicationName string
}
v.ApplicationName = config.ApplicationName
err := executeTemplate(w, "index.html", &v)
if err != nil {
log.Printf("Error executing temlate \"index.html\": %s", err.Error())
}
}
func videoIndexHandler(w http.ResponseWriter, r *http.Request) {
var index VideoIndex
index.Success = true
index.Generation = config.Generation
dir, err := os.ReadDir(path.Join(config.DataDirectory, "video"))
if err != nil {
log.Printf("can't red video directory: %s", err.Error())
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
for _, entry := range dir {
if entry.Type().IsRegular() && path.Ext(entry.Name()) == ".json" && entry.Name() != "index.json" {
var v Video
rawInfo, err := ioutil.ReadFile(path.Join(config.DataDirectory, "video", entry.Name()))
if err != nil {
log.Printf("can't read info for %s: %s", entry.Name(), err.Error())
continue
}
err = json.Unmarshal(rawInfo, &v)
if err != nil {
log.Printf("can't read info for %s: %s", entry.Name(), err.Error())
continue
}
index.Videos = append(index.Videos, v)
index.Count++
}
}
indexRaw, err := json.Marshal(index)
if err != nil {
log.Printf("can't marshal index: %s", err.Error())
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write(indexRaw)
}
func executeTemplate(w http.ResponseWriter, name string, data interface{}) (err error) {
var buf bytes.Buffer
bufferRW := bufio.NewReadWriter(bufio.NewReader(&buf), bufio.NewWriter(&buf))
err = templates.ExecuteTemplate(bufferRW, name, data)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
bufferRW.Flush()
w.WriteHeader(http.StatusOK)
io.Copy(w, bufferRW)
return
}
func rescanFiles() {
var index VideoIndex
index.Generation = config.Generation
index.Success = true
dirPath := path.Join(config.DataDirectory, "video")
dir, err := os.ReadDir(dirPath)
if err != nil {
log.Printf("can't read data directory: %s", err.Error())
}
for _, entry := range dir {
if entry.Type().IsRegular() {
if !strings.HasSuffix(entry.Name(), ".json") {
var v Video
file, err := os.Open(path.Join(dirPath, entry.Name()))
if err != nil {
log.Printf("can't read info file: %s", err.Error())
}
v.Name = entry.Name()
hashsum := md5.New()
_, err = io.Copy(hashsum, file)
if err != nil {
log.Printf("can't read info file: %s", err.Error())
}
hashstring := fmt.Sprintf("%x", hashsum.Sum(nil))
v.ID = hashstring
ext := path.Ext(entry.Name())
err = os.Rename(path.Join(dirPath, entry.Name()), path.Join(dirPath, string(hashstring)+ext))
if err != nil {
log.Printf("can't move file: %s", err.Error())
}
if info, _ := os.Stat(path.Join(dirPath, v.ID+".json")); info == nil {
rawInfo, err := json.Marshal(&v)
if err != nil {
log.Printf("can't write info: %s", err.Error())
}
err = ioutil.WriteFile(path.Join(dirPath, v.ID+".json"), rawInfo, os.ModePerm)
if err != nil {
log.Printf("can't write info: %s", err.Error())
}
}
index.Videos = append(index.Videos, v)
index.Count++
}
}
}
rawIndex, err := json.Marshal(&index)
if err != nil {
log.Fatalf("can't create index: %s", err)
}
err = ioutil.WriteFile(path.Join(dirPath, "index.json"), rawIndex, os.ModePerm)
if err != nil {
log.Fatalf("can't create index: %s", err)
}
}