package helpers import ( "embed" "fmt" "io/fs" "net/http" "os" "strconv" "time" "github.com/gin-contrib/static" "github.com/gin-gonic/gin" "github.com/labstack/echo" ) func SetCorsAndNoCacheHeaders() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", "*") c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } } type embedFileSystem struct { http.FileSystem indexes bool } func (e embedFileSystem) Exists(_ string, path string) bool { f, err := e.Open(path) if err != nil { return false } // check if indexing is allowed s, _ := f.Stat() if s.IsDir() && !e.indexes { return false } return true } func EmbedFolder(fsEmbed embed.FS, targetPath string, index bool) static.ServeFileSystem { subFS, err := fs.Sub(fsEmbed, targetPath) if err != nil { panic(err) } return embedFileSystem{ FileSystem: http.FS(subFS), indexes: index, } } func SendSong(ctx echo.Context, Filename string) error { fmt.Println("Client requests: " + Filename) //Check if file exists and open openFile, err := os.Open(Filename) if err != nil { //File not found, send 404 //http.Error(ctx.Writer, "Song not found.", 404) return ctx.String(http.StatusNotFound, "Song not found.") } defer func(openFile *os.File) { _ = openFile.Close() }(openFile) //Close after function return //File is found, create and send the correct headers //Get the Content-Type of the file //Create a buffer to store the header of the file in FileHeader := make([]byte, 512) //Copy the headers into the FileHeader buffer _, _ = openFile.Read(FileHeader) //Get content type of file //FileContentType := http.DetectContentType(FileHeader) //Get the file size FileStat, _ := openFile.Stat() //Get info from file FileSize := strconv.FormatInt(FileStat.Size(), 10) //Get file size as a string //Send the headers //writer.Header().Set("Content-Disposition", "attachment; filename="+Filename) ctx.Response().Header().Set("Content-Type", "audio/mpeg") ctx.Response().Header().Set("Content-Length", FileSize) ctx.Response().Header().Set("Expires", "Tue, 03 Jul 2001 06:00:00 GMT") ctx.Response().Header().Set("Last-Modified", time.Now().String()+" GMT") ctx.Response().Header().Set("Cache-Control", "no-cache, no-store, private, max-age=0") ctx.Response().Header().Set("Pragma", "no-cache") ctx.Response().Header().Set("X-Accel-Expires", "0") var etagHeaders = []string{ "ETag", "If-Modified-Since", "If-Match", "If-None-Match", "If-Range", "If-Unmodified-Since", } for _, v := range etagHeaders { if ctx.Request().Header.Get(v) != "" { ctx.Request().Header.Del(v) } } //Send the file //We read 512 bytes from the file already, so we reset the offset back to 0 _, _ = openFile.Seek(0, 0) //_, _ = io.Copy(ctx.Writer, openFile) //'Copy' the file to the client return ctx.Stream(http.StatusOK, "audio/mpeg", openFile) }