完成Web ASM

This commit is contained in:
Misaki
2026-06-08 22:09:35 +08:00
parent e565b80bc2
commit 36660519c1
28 changed files with 1148 additions and 178 deletions
+56
View File
@@ -0,0 +1,56 @@
package main
import (
"embed"
"flag"
"fmt"
"io/fs"
"log"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
)
//go:embed all:static/dist
var staticFiles embed.FS
func main() {
port := flag.Int("port", 8080, "server port")
flag.Parse()
distFS, err := fs.Sub(staticFiles, "static/dist")
if err != nil {
log.Fatalf("failed to open embedded files: %v", err)
}
mux := http.NewServeMux()
stripped, err := fs.Sub(distFS, ".")
if err != nil {
log.Fatalf("failed to sub: %v", err)
}
fileServer := http.FileServer(http.FS(stripped))
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, ".wasm") {
w.Header().Set("Content-Type", "application/wasm")
}
fileServer.ServeHTTP(w, r)
})
go func() {
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("shutting down...")
os.Exit(0)
}()
log.Printf("ncmdump-web (WASM mode) starting on :%d", *port)
addr := fmt.Sprintf(":%d", *port)
if err := http.ListenAndServe(addr, mux); err != nil {
log.Fatalf("server error: %v", err)
}
}
+114
View File
@@ -0,0 +1,114 @@
//go:build js && wasm
package main
import (
"bytes"
"syscall/js"
"git.taurusxin.com/taurusxin/ncmdump-go/ncmcrypt"
)
func convertNcm(this js.Value, args []js.Value) interface{} {
if len(args) < 1 {
return errorResult("no data provided")
}
dataLen := args[0].Get("byteLength").Int()
if dataLen == 0 {
return errorResult("empty data")
}
data := make([]byte, dataLen)
js.CopyBytesToGo(data, args[0])
ncm, err := ncmcrypt.NewNeteaseCloudMusicFromBytes(data)
if err != nil {
return errorResult(err.Error())
}
defer ncm.Close()
var buf bytes.Buffer
if err := ncm.DumpStream(&buf, nil); err != nil {
return errorResult(err.Error())
}
format := ncm.GetFormat()
result := js.Global().Get("Uint8Array").New(js.ValueOf(buf.Len()))
js.CopyBytesToJS(result, buf.Bytes())
meta := ncm.GetMetadata()
return js.ValueOf(map[string]interface{}{
"data": result,
"format": format,
"title": meta["title"],
"artist": meta["artist"],
"album": meta["album"],
"coverUrl": meta["coverUrl"],
})
}
func embedMetadata(this js.Value, args []js.Value) interface{} {
if len(args) < 2 {
return errorResult("insufficient arguments")
}
audioLen := args[0].Get("byteLength").Int()
audio := make([]byte, audioLen)
js.CopyBytesToGo(audio, args[0])
format := args[1].String()
title := ""
artist := ""
album := ""
var coverData []byte
if len(args) > 2 && args[2].Type() == js.TypeObject {
opts := args[2]
if v := opts.Get("title"); v.Type() == js.TypeString {
title = v.String()
}
if v := opts.Get("artist"); v.Type() == js.TypeString {
artist = v.String()
}
if v := opts.Get("album"); v.Type() == js.TypeString {
album = v.String()
}
if v := opts.Get("coverData"); v.Type() != js.TypeUndefined && v.Type() != js.TypeNull {
coverLen := v.Get("byteLength").Int()
coverData = make([]byte, coverLen)
js.CopyBytesToGo(coverData, v)
}
}
result, err := ncmcrypt.EmbedMetadata(audio, format, title, artist, album, coverData)
if err != nil {
return errorResult(err.Error())
}
out := js.Global().Get("Uint8Array").New(js.ValueOf(len(result)))
js.CopyBytesToJS(out, result)
return js.ValueOf(map[string]interface{}{
"data": out,
"format": format,
})
}
func errorResult(msg string) js.Value {
return js.ValueOf(map[string]interface{}{
"error": msg,
})
}
func main() {
js.Global().Set("ncmdumpConvert", js.FuncOf(convertNcm))
js.Global().Set("ncmdumpEmbed", js.FuncOf(embedMetadata))
ready := js.Global().Get("ncmdumpOnReady")
if ready.Type() == js.TypeFunction {
ready.Invoke()
}
select {}
}