soundr/webRoutes.go

346 lines
10 KiB
Go

package main
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"time"
"github.com/gopxl/beep/speaker"
"github.com/h2non/filetype"
)
func handlePlay(w http.ResponseWriter, r *http.Request) {
// Rejct everything else then GET requests
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json") // Set the content type to json
var cnt = r.URL.Query().Get("file") // Retrieve the file name from the query string
bytArr, err := base64.StdEncoding.DecodeString(cnt) // Decode the base64 string
if err != nil {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\""+err.Error()+"\"}")
return
}
loop := r.URL.Query().Get("loop") // Retrieve the loop value from the query string
loopBool := false
if loop == "true" {
loopBool = true
}
wantedId := r.URL.Query().Get("id") // Retrieve the id value from the query string, it's optional
t, err := os.Stat("./sounds/" + string(bytArr[:])) // Check if the file exists
if errors.Is(err, os.ErrNotExist) {
w.WriteHeader(400)
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file not found\"}")
return
}
if t.IsDir() { // Make sure it is not a folder we are trying to play
w.WriteHeader(400)
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"target is folder\"}")
return
}
buf, _ := ioutil.ReadFile("sounds/" + string(bytArr[:]))
kind, _ := filetype.Match(buf)
if kind == filetype.Unknown {
fmt.Println("Unknown file type")
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file has unknown type\"}")
return
}
if kind.MIME.Type != "audio" {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file is not an audio file\"}")
return
}
var currIndex = len(playbacks) // Create a new index for the playback
if len(wantedId) > 0 { // If the id is set, check if it is already in use
id, err := strconv.Atoi(wantedId)
if err != nil {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"id is not a number\"}")
return
}
if _, ok := playbacks[id]; ok {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"id is already in use\"}")
return
}
currIndex = id
}
fmt.Fprintf(w, "{\"status\":\"ok\", \"id\":%d}", currIndex) // Return a JSON object to the user
go PlaySound(string(bytArr[:]), currIndex, loopBool) // Play the sound
}
// Handle Buffering
func handleBufferAll(w http.ResponseWriter, r *http.Request) {
// Rejct everything else then GET requests
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json") // Set the content type to json
var temp []string
files, err := ioutil.ReadDir("./sounds/") // Read the directory
if err != nil {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\""+err.Error()+"\"}")
return
}
// Loop through the files and add the file name to the temp array
// Also triggers the buffer process for the file
for _, f := range files {
buf, _ := ioutil.ReadFile("sounds/" + string(f.Name()))
kind, _ := filetype.Match(buf)
if kind == filetype.Unknown {
fmt.Println("Unknown file type")
continue
}
if kind.MIME.Type != "audio" {
fmt.Println("Not an audio file")
continue
}
temp = append(temp, f.Name())
go BufferSound(f.Name())
time.Sleep(200 * time.Millisecond) // Wait a bit to not overload the system
}
// Return the amount of files buffered
fmt.Fprintf(w, "{\"status\":\"ok\", \"amount\":%d}", len(temp))
}
func handleBuffer(w http.ResponseWriter, r *http.Request) {
// Rejct everything else then GET requests
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json") // Set the content type to json
var cnt = r.URL.Query().Get("file") // Retrieve the file name from the query string
bytArr, err := base64.StdEncoding.DecodeString(cnt) // Decode the base64 string
if err != nil {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\""+err.Error()+"\"}")
return
}
t, err := os.Stat("./sounds/" + string(bytArr[:])) // Check if the file exists
if errors.Is(err, os.ErrNotExist) {
w.WriteHeader(400)
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file not found\"}")
return
}
if t.IsDir() { // Make sure it is not a folder we are trying to play
w.WriteHeader(400)
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"target is folder\"}")
return
}
buf, _ := ioutil.ReadFile("sounds/" + string(bytArr[:]))
kind, _ := filetype.Match(buf)
if kind == filetype.Unknown {
fmt.Println("Unknown file type")
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file has unknown type\"}")
return
}
if kind.MIME.Type != "audio" {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file is not an audio file\"}")
return
}
fmt.Fprintf(w, "{\"status\":\"ok\"}")
go BufferSound(string(bytArr[:]))
}
// Handeling Stop
func handleStop(w http.ResponseWriter, r *http.Request) {
// Rejct everything else then GET requests
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json") // Set the content type to json
var cnt, err = strconv.Atoi(r.URL.Query().Get("id")) // Retrieve the id, first convert it to an int
if err != nil {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"invalid id\"}")
}
value, ok := playbacks[cnt] // Get value from playbacks map
if !ok {
w.WriteHeader(400)
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"audio not playing\"}")
} else {
fmt.Fprintf(w, "{\"status\":\"ok\"}")
// Stop by pausing first then, set the streamer to nil. Finally delete it from the map
value.Control.Paused = true
value.Control.Streamer = nil
delete(playbacks, cnt)
}
}
func handleStopAll(w http.ResponseWriter, r *http.Request) {
// Rejct everything else then GET requests
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json") // Set the content type to json
// Pause and stop all playbacks
for _, v := range playbacks {
v.Control.Paused = true
v.Control.Streamer = nil
}
speaker.Clear() // Clear the speaker and make it shut up
// Reset the map
playbacks = make(map[int]playback)
fmt.Fprintf(w, "{\"status\":\"ok\"}")
}
func handleCurrent(w http.ResponseWriter, r *http.Request) {
// Rejct everything else then GET requests
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json") // Set the content type to json
for i := 0; i < len(playbacks); i++ {
plyB := playbacks[i]
seeker := plyB.Streamer
format := plyB.Format
if seeker != nil {
fmt.Println(format.SampleRate)
// fmt.Println(plyB.Seeker.)
position := plyB.Format.SampleRate.D(seeker.Position())
length := plyB.Format.SampleRate.D(seeker.Len())
remaining := length - position
if remaining == 0 {
plyB.Done <- true
}
}
}
var tempResultSet map[int]playbackWebReturn = make(map[int]playbackWebReturn) // Create a new map to store the results
// Iterate through the playbacks map and add important information to the tempResultSet map
for index, element := range playbacks {
tempResultSet[index] = playbackWebReturn{File: element.File, IsLoaded: element.IsLoaded, Id: index}
}
// Convert the map to a JSON object and return it to the user
j, err := json.Marshal(tempResultSet)
if err != nil {
fmt.Printf("Error: %s", err.Error())
} else {
fmt.Println(string(j))
fmt.Fprintf(w, string(j))
}
}
func handleListing(w http.ResponseWriter, r *http.Request) {
// Rejct everything else then GET requests
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json") // Set the content type to json
var temp [][3]string
files, err := ioutil.ReadDir("./sounds/") // Find all files in the sounds directory
if err != nil {
log.Fatal(err)
}
// Add the file data to the temp array
for _, f := range files {
var soundObj [3]string
soundObj[0] = f.Name()
soundObj[1] = base64.StdEncoding.EncodeToString([]byte(f.Name()))
soundObj[2] = r.URL.Host + "/v1/play?file=" + soundObj[1]
buf, _ := ioutil.ReadFile("sounds/" + f.Name())
kind, _ := filetype.Match(buf)
fmt.Println(f.Name() + " " + kind.MIME.Type)
if kind == filetype.Unknown {
fmt.Println("Unknown file type")
continue
}
if kind.MIME.Type != "audio" {
fmt.Println("Not an audio file")
continue
}
temp = append(temp, soundObj)
}
// Convert the array to a JSON object and return it to the user
j, err := json.Marshal(temp)
if err != nil {
fmt.Printf("Error: %s", err.Error())
} else {
fmt.Println(string(j))
fmt.Fprintf(w, string(j))
}
}
func handleRemaining(w http.ResponseWriter, r *http.Request) {
// Rejct everything else then GET requests
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json") // Set the content type to json
var cnt, err = strconv.Atoi(r.URL.Query().Get("id")) // Retrieve the id, first convert it to an int
if err != nil {
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"invalid id\"}")
return
}
fmt.Println(cnt)
plyB := playbacks[cnt]
// fmt.Println(beep.SampleRate.D(plyB.Streamer.Stream().Len()))
seeker := plyB.Streamer
format := plyB.Format
n := plyB.Format.SampleRate // Streamer.Stream() // .At(beep.SampleRate.D(plyB.Streamer.Stream().Len()))
if seeker != nil {
fmt.Println(format.SampleRate)
// fmt.Println(plyB.Seeker.)
position := plyB.Format.SampleRate.D(seeker.Position())
length := plyB.Format.SampleRate.D(seeker.Len())
remaining := length - position
if remaining == 0 {
plyB.Done <- true
}
fmt.Println(position)
fmt.Fprintf(w, "{\"status\":\"ok\", \"id\":%d, \"SampleRate\":%d, \"Length\":%d, \"Position\":%d, \"Remaining\": %d, \"LengthSec\":\"%v\", \"PosSec\":\"%v\", \"RemaningSec\":\"%v\"}", cnt, n, length, position, remaining, length, position, remaining)
} else {
fmt.Println("Seeker is nil")
fmt.Fprintf(w, "{\"status\":\"ok\", \"SampleRate\":%d}", n)
}
}
func handleRoot(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Soundr is running.")
}