mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-25 17:44:13 +08:00
Merge pull request #461 from InfinityPacer/codex/feat/local-plugin-paths
This commit is contained in:
@@ -118,6 +118,9 @@ const iconPath: Ref<string> = computed(() => {
|
||||
function visitPluginPage() {
|
||||
// 将raw.githubusercontent.com转换为项目地址
|
||||
let repoUrl = props.plugin?.repo_url
|
||||
if (props.plugin?.is_local || repoUrl?.startsWith('local://')) {
|
||||
repoUrl = props.plugin?.author_url
|
||||
}
|
||||
if (repoUrl) {
|
||||
if (repoUrl.includes('raw.githubusercontent.com')) {
|
||||
if (!repoUrl.endsWith('/')) repoUrl += '/'
|
||||
|
||||
@@ -1467,6 +1467,9 @@ export default {
|
||||
logFileFormatHint: 'Set the output format of log files to customize the displayed content of logs',
|
||||
pluginAutoReload: 'Plugin Hot Reload',
|
||||
pluginAutoReloadHint: 'Automatically reload after modifying plugin files, used when developing plugins',
|
||||
pluginLocalRepoPaths: 'Local Plugin Repository Paths',
|
||||
pluginLocalRepoPathsHint:
|
||||
'Local plugin repository directories. Separate multiple directories with commas. Relative and absolute paths are supported.',
|
||||
encodingDetectionPerformanceMode: 'Encoding Detection Performance Mode',
|
||||
encodingDetectionPerformanceModeHint:
|
||||
'Prioritize detection efficiency, but may reduce encoding detection accuracy',
|
||||
@@ -2602,6 +2605,7 @@ export default {
|
||||
settings: 'Settings',
|
||||
projectHome: 'Project Home',
|
||||
updateHistory: 'Update History',
|
||||
local: 'Local',
|
||||
installToLocal: 'Install to Local',
|
||||
totalDownloads: 'Total {count} downloads',
|
||||
viewData: 'View Data',
|
||||
|
||||
@@ -1459,6 +1459,8 @@ export default {
|
||||
logFileFormatHint: '设置日志文件的输出格式,用于自定义日志的显示内容',
|
||||
pluginAutoReload: '插件热加载',
|
||||
pluginAutoReloadHint: '修改插件文件后自动重新加载,开发插件时使用',
|
||||
pluginLocalRepoPaths: '本地插件仓库路径',
|
||||
pluginLocalRepoPathsHint: '本地插件仓库目录,多个目录用英文逗号分隔,支持相对路径和绝对路径',
|
||||
encodingDetectionPerformanceMode: '编码探测性能模式',
|
||||
encodingDetectionPerformanceModeHint: '优先提升探测效率,但可能降低编码探测的准确性',
|
||||
transferThreads: '文件整理线程数',
|
||||
@@ -2573,6 +2575,7 @@ export default {
|
||||
settings: '设置',
|
||||
projectHome: '项目主页',
|
||||
updateHistory: '更新说明',
|
||||
local: '本地',
|
||||
installToLocal: '安装到本地',
|
||||
totalDownloads: '共 {count} 次下载',
|
||||
viewData: '查看数据',
|
||||
|
||||
@@ -1461,6 +1461,8 @@ export default {
|
||||
logFileFormatHint: '設置日誌文件的輸出格式,用於自定義日誌的顯示內容',
|
||||
pluginAutoReload: '插件熱加載',
|
||||
pluginAutoReloadHint: '修改插件文件後自動重新加載,開發插件時使用',
|
||||
pluginLocalRepoPaths: '本地插件倉庫路徑',
|
||||
pluginLocalRepoPathsHint: '本地插件倉庫目錄,多個目錄用英文逗號分隔,支持相對路徑和絕對路徑',
|
||||
encodingDetectionPerformanceMode: '編碼探測性能模式',
|
||||
encodingDetectionPerformanceModeHint: '優先提升探測效率,但可能降低編碼探測的準確性',
|
||||
transferThreads: '文件整理線程數',
|
||||
@@ -2575,6 +2577,7 @@ export default {
|
||||
settings: '設置',
|
||||
projectHome: '項目主頁',
|
||||
updateHistory: '更新說明',
|
||||
local: '本地',
|
||||
installToLocal: '安裝到本地',
|
||||
totalDownloads: '共 {count} 次下載',
|
||||
viewData: '查看數據',
|
||||
|
||||
@@ -34,6 +34,9 @@ const activeTab = ref('installed')
|
||||
// 获取插件标签页
|
||||
const pluginTabs = computed(() => getPluginTabs(t))
|
||||
|
||||
// 本地插件来源显示名称
|
||||
const localRepoLabel = computed(() => t('plugin.local'))
|
||||
|
||||
// 使用动态标签页
|
||||
const { registerHeaderTab } = useDynamicHeaderTab()
|
||||
|
||||
@@ -610,15 +613,17 @@ async function saveFolderPluginOrder() {
|
||||
|
||||
// 初始化过滤选项
|
||||
function initOptions(item: Plugin) {
|
||||
const optionValue = (options: Array<string>, value: string | undefined) => {
|
||||
value && !options.includes(value) && options.push(value)
|
||||
const optionValue = (options: Array<string>, value: string | undefined, preferred = false) => {
|
||||
if (!value || options.includes(value)) return
|
||||
if (preferred) options.unshift(value)
|
||||
else options.push(value)
|
||||
}
|
||||
const optionMutipleValue = (options: Array<string>, value: string | undefined) => {
|
||||
value && value.split(',').forEach(v => !options.includes(v) && options.push(v))
|
||||
}
|
||||
optionValue(authorFilterOptions.value, item.plugin_author)
|
||||
optionMutipleValue(labelFilterOptions.value, item.plugin_label)
|
||||
optionValue(repoFilterOptions.value, handleRepoUrl(item.repo_url))
|
||||
optionValue(repoFilterOptions.value, handleRepoUrl(item), Boolean(item.is_local || item.repo_url?.startsWith('local://')))
|
||||
}
|
||||
|
||||
// 关闭插件市场窗口
|
||||
@@ -650,7 +655,7 @@ async function installPlugin(item: Plugin) {
|
||||
enabledFilter.value = false
|
||||
installedFilter.value = null
|
||||
// 刷新
|
||||
refreshData()
|
||||
await refreshData()
|
||||
} else {
|
||||
$toast.error(t('plugin.installFailed', { name: item?.plugin_name, message: result.message }))
|
||||
}
|
||||
@@ -750,6 +755,7 @@ async function fetchUninstalledPlugins(force: boolean = false) {
|
||||
// 排除已安装且有更新的,上面的问题在于"本地存在未安装的旧版本插件且云端有更新时"不会在插件市场展示
|
||||
marketList.value = uninstalledList.value.filter(item => !(item.has_update && item.installed))
|
||||
// 初始化过滤选项
|
||||
repoFilterOptions.value = []
|
||||
marketList.value.forEach(initOptions)
|
||||
// 设置APP市场加载完成
|
||||
isAppMarketLoaded.value = true
|
||||
@@ -770,13 +776,14 @@ async function getPluginStatistics() {
|
||||
// 加载所有数据
|
||||
async function refreshData() {
|
||||
await fetchInstalledPlugins()
|
||||
fetchUninstalledPlugins()
|
||||
await fetchUninstalledPlugins()
|
||||
getPluginStatistics()
|
||||
// 重新加载文件夹配置,确保分身插件能正确显示在文件夹中
|
||||
await loadPluginFolders()
|
||||
}
|
||||
|
||||
// 对uninstalledList进行排序到sortedUninstalledList
|
||||
watch([marketList, filterForm, activeSort], () => {
|
||||
watch([marketList, filterForm, activeSort, PluginStatistics], () => {
|
||||
// 匹配过滤函数
|
||||
const match = (filter: Array<string>, value: string | undefined) =>
|
||||
filter.length === 0 || (value && filter.includes(value))
|
||||
@@ -794,7 +801,7 @@ watch([marketList, filterForm, activeSort], () => {
|
||||
filterText(filterForm.name, `${value.plugin_name} ${value.plugin_desc}`) &&
|
||||
match(filterForm.author, value.plugin_author) &&
|
||||
matchMultiple(filterForm.label, value.plugin_label) &&
|
||||
match(filterForm.repo, handleRepoUrl(value.repo_url))
|
||||
match(filterForm.repo, handleRepoUrl(value))
|
||||
) {
|
||||
sortedUninstalledList.value.push(value)
|
||||
}
|
||||
@@ -805,7 +812,7 @@ watch([marketList, filterForm, activeSort], () => {
|
||||
if (!isNullOrEmptyObject(PluginStatistics.value)) {
|
||||
if (!activeSort.value || activeSort.value === 'count') {
|
||||
sortedUninstalledList.value = sortedUninstalledList.value.sort((a, b) => {
|
||||
return PluginStatistics.value[b.id || '0'] - PluginStatistics.value[a.id || '0']
|
||||
return (PluginStatistics.value[b.id || '0'] ?? 0) - (PluginStatistics.value[a.id || '0'] ?? 0)
|
||||
})
|
||||
} else if (activeSort.value) {
|
||||
sortedUninstalledList.value = sortedUninstalledList.value.sort((a: any, b: any) => {
|
||||
@@ -825,9 +832,9 @@ function pluginLabels(label: string | undefined) {
|
||||
}
|
||||
|
||||
// 新安装了插件
|
||||
function pluginInstalled() {
|
||||
async function pluginInstalled() {
|
||||
pluginDialogClose()
|
||||
refreshData()
|
||||
await refreshData()
|
||||
}
|
||||
|
||||
// 插件市场设置完成
|
||||
@@ -842,7 +849,7 @@ async function refreshMarket() {
|
||||
isMarketRefreshing.value = true
|
||||
try {
|
||||
await fetchUninstalledPlugins(true)
|
||||
await getPluginStatistics()
|
||||
getPluginStatistics()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
@@ -850,9 +857,22 @@ async function refreshMarket() {
|
||||
}
|
||||
}
|
||||
|
||||
function parseLocalRepoPath(repoUrl: string | undefined) {
|
||||
if (!repoUrl?.startsWith('local://')) return ''
|
||||
|
||||
try {
|
||||
return new URL(repoUrl).searchParams.get('path') || ''
|
||||
} catch (error) {
|
||||
return decodeURIComponent(repoUrl.match(/[?&]path=([^&]+)/)?.[1] || '')
|
||||
}
|
||||
}
|
||||
|
||||
// 处理掉github地址的前缀
|
||||
function handleRepoUrl(url: string | undefined) {
|
||||
function handleRepoUrl(item: Plugin | string | undefined) {
|
||||
const url = typeof item === 'string' ? item : item?.repo_url
|
||||
if (!url) return ''
|
||||
if (url.startsWith('local://')) return parseLocalRepoPath(url) || localRepoLabel.value
|
||||
if (typeof item !== 'string' && item?.is_local) return parseLocalRepoPath(url) || localRepoLabel.value
|
||||
return url.replace('https://github.com/', '').replace('https://raw.githubusercontent.com/', '')
|
||||
}
|
||||
|
||||
@@ -886,7 +906,6 @@ onMounted(async () => {
|
||||
await loadPluginOrderConfig()
|
||||
await loadPluginFolders() // 加载文件夹配置
|
||||
await refreshData()
|
||||
getPluginStatistics()
|
||||
if (activeTab.value != 'market' && pluginId.value) {
|
||||
// 找到这个插件
|
||||
const plugin = dataList.value.find(item => item.id === pluginId.value)
|
||||
|
||||
@@ -84,6 +84,7 @@ const SystemSettings = ref<any>({
|
||||
LOG_FILE_FORMAT: '【%(levelname)s】%(asctime)s - %(message)s',
|
||||
// 实验室
|
||||
PLUGIN_AUTO_RELOAD: false,
|
||||
PLUGIN_LOCAL_REPO_PATHS: '',
|
||||
ENCODING_DETECTION_PERFORMANCE_MODE: true,
|
||||
TRANSFER_THREADS: 1,
|
||||
},
|
||||
@@ -1458,6 +1459,15 @@ onDeactivated(() => {
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
v-model="SystemSettings.Advanced.PLUGIN_LOCAL_REPO_PATHS"
|
||||
:label="t('setting.system.pluginLocalRepoPaths')"
|
||||
:hint="t('setting.system.pluginLocalRepoPathsHint')"
|
||||
persistent-hint
|
||||
prepend-inner-icon="mdi-folder-code"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VSwitch
|
||||
v-model="SystemSettings.Advanced.ENCODING_DETECTION_PERFORMANCE_MODE"
|
||||
|
||||
Reference in New Issue
Block a user