133 lines
3.7 KiB
Go
133 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
ihttp "dwelling-radio/internal/http"
|
|
"dwelling-radio/internal/radio"
|
|
sqlite_stats "dwelling-radio/internal/statistics/db/sqlite"
|
|
"dwelling-radio/pkg/utils"
|
|
"dwelling-radio/web"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"path"
|
|
"syscall"
|
|
|
|
"git.arav.su/Arav/httpr"
|
|
)
|
|
|
|
var (
|
|
listenAddress = flag.String("listen", "/var/run/dwelling-radio/sock", "listen address (ip:port|unix_path)")
|
|
workDirPath = flag.String("work-dir", "/mnt/data/appdata/radio", "path to a working directory")
|
|
playlistName = flag.String("playlist", "all-rand", "a playlist name")
|
|
songListLen = flag.Int64("list-length", 10, "number of songs to show in last N songs table")
|
|
|
|
showVersion = flag.Bool("v", false, "show version")
|
|
)
|
|
|
|
var version string
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
log.SetFlags(log.Lshortfile)
|
|
|
|
if *showVersion {
|
|
fmt.Println("dwelling-radio ver.", version, "\nCopyright (c) 2022-2024 Alexander \"Arav\" Andreev <me@arav.su>")
|
|
return
|
|
}
|
|
|
|
stats, err := sqlite_stats.New(path.Join(*workDirPath, "statistics.db3"))
|
|
if err != nil {
|
|
log.Fatalln("Statistics:", err)
|
|
}
|
|
defer stats.Close()
|
|
|
|
currentSong := radio.Song{}
|
|
lstnrs := radio.NewListenerCounter()
|
|
|
|
plylst, err := radio.NewPlaylist(path.Join(*workDirPath, "playlists", *playlistName), true)
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
|
|
r := httpr.New()
|
|
|
|
r.Handler(http.MethodGet, "/", func(w http.ResponseWriter, r *http.Request) {
|
|
lst, err := stats.LastNSongs(*songListLen)
|
|
if err != nil {
|
|
log.Printf("Failed to fetch last N songs: %s\n", err)
|
|
}
|
|
|
|
lstnrs.RLock()
|
|
defer lstnrs.RUnlock()
|
|
web.Index(¤tSong, lst, *songListLen, lstnrs, r).Render(context.Background(), w)
|
|
})
|
|
|
|
r.Handler(http.MethodGet, "/filelist", func(w http.ResponseWriter, r *http.Request) {
|
|
data, err := os.ReadFile(path.Join(*workDirPath, "filelist.html"))
|
|
if err != nil {
|
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
w.Header().Add("Content-Type", "text/html")
|
|
w.Header().Add("Link", "<"+utils.Site(r.Host)+"/filelist>; rel=\"canonical\"")
|
|
w.Write(data)
|
|
})
|
|
|
|
r.Handler(http.MethodGet, "/playlist", web.ServeAsset("playlist.m3u", "", "radio.arav.su.m3u"))
|
|
|
|
r.Handler(http.MethodGet, "/robots.txt", web.ServeAsset("robots.txt", "text/plain", ""))
|
|
r.Handler(http.MethodGet, "/sitemap.xml", web.ServeAsset("sitemap.xml", "application/xml", ""))
|
|
r.Handler(http.MethodGet, "/favicon.svg", web.ServeAsset("favicon.svg", "image/svg", ""))
|
|
|
|
r.ServeStatic("/assets/*filepath", web.Assets())
|
|
|
|
djh := ihttp.NewDJHandlers(lstnrs, plylst, stats, ¤tSong, *songListLen, path.Join(*workDirPath, "fallback.ogg"))
|
|
|
|
s := r.Sub("/api")
|
|
|
|
s.Handler(http.MethodPost, "/listener/icecast", djh.ListenersUpdateIcecast)
|
|
s.Handler(http.MethodGet, "/playlist", djh.PlaylistNext)
|
|
s.Handler(http.MethodGet, "/status", djh.Status)
|
|
|
|
srv := ihttp.NewHttpServer(r)
|
|
|
|
if err := srv.Start(*listenAddress); err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
|
|
defer func() {
|
|
if err := srv.Stop(); err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
}()
|
|
|
|
sysSignal := make(chan os.Signal, 1)
|
|
signal.Notify(sysSignal, os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGABRT, syscall.SIGSEGV, syscall.SIGHUP)
|
|
|
|
for {
|
|
switch <-sysSignal {
|
|
case os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGABRT, syscall.SIGSEGV:
|
|
if currentSong.Artist != "" {
|
|
lstnrs.Lock()
|
|
defer lstnrs.Unlock()
|
|
currentSong.Listeners, currentSong.PeakListeners = lstnrs.Reset()
|
|
if err := stats.Add(¤tSong); err != nil {
|
|
log.Println("failed to save a current song during a shutdown:", err)
|
|
}
|
|
}
|
|
return
|
|
case syscall.SIGHUP:
|
|
plylst.Lock()
|
|
defer plylst.Unlock()
|
|
if err := plylst.Reload(); err != nil {
|
|
log.Println(err)
|
|
}
|
|
}
|
|
}
|
|
}
|