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

160 lines
3.9 KiB
Go

package extension_repo
import (
"errors"
"fmt"
"regexp"
"seanime/internal/extension"
"seanime/internal/util"
"strings"
)
func pluginManifestSanityCheck(ext *extension.Extension) error {
// Not a plugin, so no need to check
if ext.Type != extension.TypePlugin {
return nil
}
// Check plugin manifest
if ext.Plugin == nil {
return fmt.Errorf("plugin manifest is missing")
}
// Check plugin manifest version
if ext.Plugin.Version == "" {
return fmt.Errorf("plugin manifest version is missing")
}
// Check plugin permissions version
if ext.Plugin.Version != extension.PluginManifestVersion {
return fmt.Errorf("unsupported plugin manifest version: %v", ext.Plugin.Version)
}
return nil
}
func manifestSanityCheck(ext *extension.Extension) error {
if ext.ID == "" || ext.Name == "" || ext.Version == "" || ext.Language == "" || ext.Type == "" || ext.Author == "" {
return fmt.Errorf("extension is missing required fields, ID: %v, Name: %v, Version: %v, Language: %v, Type: %v, Author: %v, Payload: %v",
ext.ID, ext.Name, ext.Version, ext.Language, ext.Type, ext.Author, len(ext.Payload))
}
if ext.Payload == "" && ext.PayloadURI == "" {
return fmt.Errorf("extension is missing payload and payload URI")
}
// Check the ID
if err := isValidExtensionID(ext.ID); err != nil {
return err
}
// Check name length
if len(ext.Name) > 50 {
return fmt.Errorf("extension name is too long")
}
// Check author length
if len(ext.Author) > 25 {
return fmt.Errorf("extension author is too long")
}
if !util.IsValidVersion(ext.Version) {
return fmt.Errorf("invalid version: %v", ext.Version)
}
// Check language
if ext.Language != extension.LanguageGo &&
ext.Language != extension.LanguageJavascript &&
ext.Language != extension.LanguageTypescript {
return fmt.Errorf("unsupported language: %v", ext.Language)
}
// Check type
if ext.Type != extension.TypeMangaProvider &&
ext.Type != extension.TypeOnlinestreamProvider &&
ext.Type != extension.TypeAnimeTorrentProvider &&
ext.Type != extension.TypePlugin {
return fmt.Errorf("unsupported extension type: %v", ext.Type)
}
if ext.Type == extension.TypePlugin {
if err := pluginManifestSanityCheck(ext); err != nil {
return err
}
}
ext.Lang = strings.ToLower(ext.Lang)
return nil
}
// extensionSanityCheck checks if the extension has all the required fields in the manifest.
func (r *Repository) extensionSanityCheck(ext *extension.Extension) error {
if err := manifestSanityCheck(ext); err != nil {
return err
}
// Check that the ID is unique
if err := r.isUniqueExtensionID(ext.ID); err != nil {
return err
}
return nil
}
// checks if the extension ID is valid
// Note: The ID must start with a letter and contain only alphanumeric characters
// because it can either be used as a package name or appear in a filename
func isValidExtensionID(id string) error {
if id == "" {
return errors.New("extension ID is empty")
}
if len(id) > 40 {
return errors.New("extension ID is too long")
}
if len(id) < 3 {
return errors.New("extension ID is too short")
}
if !isValidExtensionIDString(id) {
return errors.New("extension ID contains invalid characters")
}
return nil
}
func isValidExtensionIDString(id string) bool {
// Check if the ID starts with a letter and contains only alphanumeric characters
re := regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9]$`)
ok := re.MatchString(id)
if !ok {
return false
}
return true
}
func (r *Repository) isUniqueExtensionID(id string) error {
// Check if the ID is not a reserved built-in extension ID
_, found := r.extensionBank.Get(id)
if found {
return errors.New("extension ID is already in use")
}
return nil
}
func ReplacePackageName(src string, newPkgName string) string {
rgxp, err := regexp.Compile(`package \w+`)
if err != nil {
return ""
}
ogPkg := rgxp.FindString(src)
if ogPkg == "" {
return src
}
return strings.Replace(src, ogPkg, "package "+newPkgName, 1)
}