196 lines
5.2 KiB
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)
|
|
}
|
|
}
|