Files
seanime-docker/seanime-2.9.10/codegen/internal/generate_hook_events_handlers.go
2025-09-20 14:08:38 +01:00

147 lines
4.9 KiB
Go

package codegen
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
// GenerateHandlerHookEvents generates hook_events.go file for handlers
func GenerateHandlerHookEvents(handlersJsonPath string, outputDir string) {
// Create output directory if it doesn't exist
err := os.MkdirAll(outputDir, os.ModePerm)
if err != nil {
panic(err)
}
// Read handlers.json
handlersJson, err := os.ReadFile(handlersJsonPath)
if err != nil {
panic(err)
}
// Parse handlers.json
var handlers []RouteHandler
err = json.Unmarshal(handlersJson, &handlers)
if err != nil {
panic(err)
}
// Create hook_events.go file
outFilePath := filepath.Join(outputDir, "hook_events.go")
f, err := os.Create(outFilePath)
if err != nil {
panic(err)
}
defer f.Close()
// Write package declaration and imports
f.WriteString("package handlers\n\n")
f.WriteString("import (\n")
//f.WriteString("\t\"seanime/internal/hook_resolver\"\n")
imports := []string{
"\"seanime/internal/api/anilist\"",
"\"seanime/internal/api/tvdb\"",
"\"seanime/internal/continuity\"",
"\"seanime/internal/database/models\"",
"\"seanime/internal/debrid/client\"",
"\"seanime/internal/debrid/debrid\"",
"\"seanime/internal/extension\"",
"hibikemanga \"seanime/internal/extension/hibike/manga\"",
"hibikeonlinestream \"seanime/internal/extension/hibike/onlinestream\"",
"hibiketorrent \"seanime/internal/extension/hibike/torrent\"",
"\"seanime/internal/extension_playground\"",
"\"seanime/internal/extension_repo\"",
"\"seanime/internal/hook_resolver\"",
"\"seanime/internal/library/anime\"",
"\"seanime/internal/library/summary\"",
"\"seanime/internal/manga\"",
"\"seanime/internal/manga/downloader\"",
"\"seanime/internal/mediastream\"",
"\"seanime/internal/onlinestream\"",
"\"seanime/internal/report\"",
"\"seanime/internal/sync\"",
"\"seanime/internal/torrent_clients/torrent_client\"",
"\"seanime/internal/torrents/torrent\"",
"\"seanime/internal/torrentstream\"",
"\"seanime/internal/updater\"",
}
for _, imp := range imports {
f.WriteString("\t" + imp + "\n")
}
f.WriteString(")\n\n")
// Generate events for each handler
for _, handler := range handlers {
// Skip if handler name is empty or doesn't start with 'Handle'
if handler.Name == "" || !strings.HasPrefix(handler.Name, "Handle") {
continue
}
// Generate the "Requested" event
f.WriteString(fmt.Sprintf("// %sRequestedEvent is triggered when %s is requested.\n", handler.Name, handler.TrimmedName))
f.WriteString("// Prevent default to skip the default behavior and return your own data.\n")
f.WriteString(fmt.Sprintf("type %sRequestedEvent struct {\n", handler.Name))
f.WriteString("\thook_resolver.Event\n")
// Add path parameters
for _, param := range handler.Api.Params {
f.WriteString(fmt.Sprintf("\t%s %s `json:\"%s\"`\n", pascalCase(param.Name), param.GoType, param.JsonName))
}
// Add body fields
for _, field := range handler.Api.BodyFields {
goType := field.GoType
if goType == "__STRUCT__" || goType == "[]__STRUCT__" || (strings.HasPrefix(goType, "map[") && strings.Contains(goType, "__STRUCT__")) {
goType = field.InlineStructType
}
goType = strings.Replace(goType, "handlers.", "", 1)
addPointer := isCustomStruct(goType)
if addPointer {
goType = "*" + goType
}
f.WriteString(fmt.Sprintf("\t%s %s `json:\"%s\"`\n", pascalCase(field.Name), goType, field.JsonName))
}
// If handler returns something other than bool or true, add a Data field to store the result
if handler.Api.ReturnGoType != "" && handler.Api.ReturnGoType != "true" && handler.Api.ReturnGoType != "bool" {
returnGoType := strings.Replace(handler.Api.ReturnGoType, "handlers.", "", 1)
addPointer := isCustomStruct(returnGoType)
if addPointer {
returnGoType = "*" + returnGoType
}
f.WriteString(fmt.Sprintf("\t// Empty data object, will be used if the hook prevents the default behavior\n"))
f.WriteString(fmt.Sprintf("\tData %s `json:\"data\"`\n", returnGoType))
}
f.WriteString("}\n\n")
// Generate the response event if handler returns something other than bool or true
if handler.Api.ReturnGoType != "" && handler.Api.ReturnGoType != "true" && handler.Api.ReturnGoType != "bool" {
returnGoType := strings.Replace(handler.Api.ReturnGoType, "handlers.", "", 1)
addPointer := isCustomStruct(returnGoType)
if addPointer {
returnGoType = "*" + returnGoType
}
f.WriteString(fmt.Sprintf("// %sEvent is triggered after processing %s.\n", handler.Name, handler.TrimmedName))
f.WriteString(fmt.Sprintf("type %sEvent struct {\n", handler.Name))
f.WriteString("\thook_resolver.Event\n")
f.WriteString(fmt.Sprintf("\tData %s `json:\"data\"`\n", returnGoType))
f.WriteString("}\n\n")
}
}
cmd := exec.Command("gofmt", "-w", outFilePath)
cmd.Run()
}
func pascalCase(s string) string {
return strings.ReplaceAll(strings.Title(strings.ReplaceAll(s, "_", " ")), " ", "")
}