mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-20 18:07:44 +02:00
feat: add button setting type for extension actions
- Add SettingTypeButton for action buttons in extension settings - Add Action field to ExtensionSetting for JS function name - Update extension detail page UI to render button settings - Add InvokeAction method to execute button actions
This commit is contained in:
@@ -959,3 +959,60 @@ func (m *ExtensionManager) UnloadAllExtensions() {
|
||||
|
||||
GoLog("[Extension] All extensions unloaded\n")
|
||||
}
|
||||
|
||||
// InvokeAction calls a custom action function on an extension (e.g., for button settings)
|
||||
// The function is called as extension.<actionName>() and can return a result
|
||||
func (m *ExtensionManager) InvokeAction(extensionID string, actionName string) (map[string]interface{}, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
ext, exists := m.extensions[extensionID]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("extension not found: %s", extensionID)
|
||||
}
|
||||
|
||||
if ext.VM == nil {
|
||||
return nil, fmt.Errorf("extension VM not initialized")
|
||||
}
|
||||
|
||||
if !ext.Enabled {
|
||||
return nil, fmt.Errorf("extension is disabled")
|
||||
}
|
||||
|
||||
// Call the action function on the extension object
|
||||
script := fmt.Sprintf(`
|
||||
(function() {
|
||||
if (typeof extension !== 'undefined' && typeof extension.%s === 'function') {
|
||||
try {
|
||||
var result = extension.%s();
|
||||
if (result && typeof result.then === 'function') {
|
||||
// Handle promise - return pending status
|
||||
return { success: true, pending: true, message: 'Action started' };
|
||||
}
|
||||
return { success: true, result: result };
|
||||
} catch (e) {
|
||||
return { success: false, error: e.toString() };
|
||||
}
|
||||
}
|
||||
return { success: false, error: 'Action function not found: %s' };
|
||||
})()
|
||||
`, actionName, actionName, actionName)
|
||||
|
||||
result, err := RunWithTimeoutAndRecover(ext.VM, script, DefaultJSTimeout)
|
||||
if err != nil {
|
||||
GoLog("[Extension] InvokeAction error for %s.%s: %v\n", extensionID, actionName, err)
|
||||
return nil, fmt.Errorf("action failed: %v", err)
|
||||
}
|
||||
|
||||
if result == nil || goja.IsUndefined(result) {
|
||||
return map[string]interface{}{"success": true}, nil
|
||||
}
|
||||
|
||||
exported := result.Export()
|
||||
if resultMap, ok := exported.(map[string]interface{}); ok {
|
||||
GoLog("[Extension] InvokeAction %s.%s result: %v\n", extensionID, actionName, resultMap)
|
||||
return resultMap, nil
|
||||
}
|
||||
|
||||
return map[string]interface{}{"success": true, "result": exported}, nil
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ const (
|
||||
SettingTypeNumber SettingType = "number"
|
||||
SettingTypeBool SettingType = "boolean"
|
||||
SettingTypeSelect SettingType = "select"
|
||||
SettingTypeButton SettingType = "button" // Action button that calls a JS function
|
||||
)
|
||||
|
||||
// ExtensionPermissions defines what resources an extension can access
|
||||
@@ -42,6 +43,7 @@ type ExtensionSetting struct {
|
||||
Secret bool `json:"secret,omitempty"`
|
||||
Default interface{} `json:"default,omitempty"`
|
||||
Options []string `json:"options,omitempty"` // For select type
|
||||
Action string `json:"action,omitempty"` // For button type: JS function name to call (e.g., "startLogin")
|
||||
}
|
||||
|
||||
// QualityOption represents a quality option for download providers
|
||||
@@ -204,6 +206,7 @@ func (m *ExtensionManifest) Validate() error {
|
||||
SettingTypeNumber: true,
|
||||
SettingTypeBool: true,
|
||||
SettingTypeSelect: true,
|
||||
SettingTypeButton: true,
|
||||
}
|
||||
if !validTypes[setting.Type] {
|
||||
return &ManifestValidationError{
|
||||
@@ -219,6 +222,14 @@ func (m *ExtensionManifest) Validate() error {
|
||||
Message: "select type requires options",
|
||||
}
|
||||
}
|
||||
|
||||
// Button type requires action
|
||||
if setting.Type == SettingTypeButton && setting.Action == "" {
|
||||
return &ManifestValidationError{
|
||||
Field: fmt.Sprintf("settings[%d].action", i),
|
||||
Message: "button type requires action (JS function name)",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user