File size: 2,898 Bytes
9361148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33a89be
9361148
 
 
 
 
 
33a89be
9361148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# -*- coding: utf-8 -*-
"""
导出插件加载器

负责扫描和加载内置及外部插件
"""

import os
import sys
import logging
import importlib.util
from typing import Dict, List, Type

from .base import ExportPlugin
from .simple_export import SimpleExportPlugin
from .utau_oto_export import UTAUOtoExportPlugin

logger = logging.getLogger(__name__)


def get_builtin_plugins() -> List[Type[ExportPlugin]]:
    """获取内置插件列表"""
    return [SimpleExportPlugin, UTAUOtoExportPlugin]


def load_plugins(plugins_dir: str = None) -> Dict[str, ExportPlugin]:
    """
    加载所有插件
    
    参数:
        plugins_dir: 外部插件目录路径,默认为 export_plugins 同级目录
    
    返回:
        {插件名称: 插件实例} 字典
    """
    plugins: Dict[str, ExportPlugin] = {}
    
    # 加载内置插件
    for plugin_cls in get_builtin_plugins():
        try:
            instance = plugin_cls()
            plugins[instance.name] = instance
            logger.info(f"加载内置插件: {instance.name}")
        except Exception as e:
            logger.error(f"加载内置插件失败: {plugin_cls.__name__}, {e}")
    
    # 加载外部插件
    if plugins_dir and os.path.exists(plugins_dir):
        for filename in os.listdir(plugins_dir):
            if filename.endswith('.py') and not filename.startswith('_'):
                plugin_path = os.path.join(plugins_dir, filename)
                try:
                    plugin = _load_plugin_from_file(plugin_path)
                    if plugin:
                        plugins[plugin.name] = plugin
                        logger.info(f"加载外部插件: {plugin.name} ({filename})")
                except Exception as e:
                    logger.error(f"加载外部插件失败: {filename}, {e}")
    
    return plugins


def _load_plugin_from_file(filepath: str) -> ExportPlugin:
    """
    从文件加载插件
    
    参数:
        filepath: 插件文件路径
    
    返回:
        插件实例,加载失败返回None
    """
    try:
        module_name = os.path.splitext(os.path.basename(filepath))[0]
        spec = importlib.util.spec_from_file_location(module_name, filepath)
        if spec is None or spec.loader is None:
            return None
        
        module = importlib.util.module_from_spec(spec)
        sys.modules[module_name] = module
        spec.loader.exec_module(module)
        
        # 查找 ExportPlugin 子类
        for attr_name in dir(module):
            attr = getattr(module, attr_name)
            if (isinstance(attr, type) and 
                issubclass(attr, ExportPlugin) and 
                attr is not ExportPlugin):
                return attr()
        
        return None
        
    except Exception as e:
        logger.error(f"加载插件文件失败: {filepath}, {e}", exc_info=True)
        return None