Compare commits

...

22 Commits
v2.5.3 ... main

Author SHA1 Message Date
jxxghp
6fdbc8104c v1.9.17 2024-09-18 17:37:57 +08:00
jxxghp
433c14679c 更新 package.json 2024-09-08 13:09:25 +08:00
jxxghp
fcaa4476f0 更新 package.json 2024-09-05 06:59:13 +08:00
jxxghp
85c5c3058c 更新 AccountSettingDirectory.vue 2024-09-05 06:57:32 +08:00
jxxghp
035122a08e Merge pull request #172 from flowclouds/main 2024-08-16 12:07:18 +08:00
jxxghp
0a76875f8e chore: update package.json version to 1.9.14-2 2024-08-16 10:10:41 +08:00
lj
218eac54ce fix: 优化代码移除相关警告 2024-08-15 15:52:32 +08:00
jxxghp
84deeff4f5 chore: update package.json version to 1.9.14-1 2024-08-12 18:13:47 +08:00
jxxghp
0c72d026f6 chore: update package.json version to 1.9.14 2024-08-08 14:37:40 +08:00
jxxghp
aec9ea83c5 更新 package.json 2024-07-30 06:33:53 +08:00
jxxghp
effd13aedd Merge pull request #171 from InfinityPacer/main 2024-07-22 22:12:19 +08:00
InfinityPacer
42b43d65d7 fix(FilterRuleCard): 移除规则中的空白字符并保留前后的空格 2024-07-22 21:47:42 +08:00
jxxghp
c501d824dd Merge pull request #170 from InfinityPacer/main 2024-07-17 06:53:43 +08:00
InfinityPacer
384ac2faf1 feat: ace-editor support python 2024-07-17 01:48:18 +08:00
jxxghp
dd2c4dd24b v1.9.12 2024-07-16 07:56:07 +08:00
jxxghp
356ffddb1c release 2024-07-09 08:00:11 +08:00
jxxghp
de69be7c4e Merge pull request #168 from s0urcelab/main 2024-07-09 06:28:30 +08:00
s0urce
e962f555ae fix: issue #167 2024-07-09 02:56:48 +08:00
jxxghp
1987246585 Merge pull request #166 from JavaZeroo/main 2024-07-08 19:05:23 +08:00
JavaZero
393264f66b 实现根据操作系统动态显示不同的搜索快捷键提示 2024-07-08 13:51:00 +08:00
jxxghp
9b50020b3b Merge pull request #165 from BrettDean/main 2024-07-05 15:26:31 +08:00
Dean
5e5545fe01 优化"最近入库"数量显示 2024-07-05 15:19:50 +08:00
14 changed files with 203 additions and 136 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "moviepilot",
"version": "1.9.10",
"version": "1.9.17",
"private": true,
"bin": "dist/service.js",
"scripts": {

View File

@@ -10,6 +10,8 @@ import modeYamlUrl from 'ace-builds/src-noconflict/mode-yaml?url'
import modeCssUrl from 'ace-builds/src-noconflict/mode-css?url'
import modePythonUrl from 'ace-builds/src-noconflict/mode-python?url'
import themeGithubUrl from 'ace-builds/src-noconflict/theme-github?url'
import themeChromeUrl from 'ace-builds/src-noconflict/theme-chrome?url'
@@ -38,6 +40,8 @@ import snippetsJsonUrl from 'ace-builds/src-noconflict/snippets/json?url'
import snippertsCssUrl from 'ace-builds/src-noconflict/snippets/css?url'
import snippetsPythonUrl from 'ace-builds/src-noconflict/snippets/python?url'
import 'ace-builds/src-noconflict/ext-language_tools'
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl)
@@ -45,6 +49,7 @@ ace.config.setModuleUrl('ace/mode/javascript', modeJavascriptUrl)
ace.config.setModuleUrl('ace/mode/html', modeHtmlUrl)
ace.config.setModuleUrl('ace/mode/yaml', modeYamlUrl)
ace.config.setModuleUrl('ace/mode/css', modeCssUrl)
ace.config.setModuleUrl('ace/mode/python', modePythonUrl)
ace.config.setModuleUrl('ace/theme/github', themeGithubUrl)
ace.config.setModuleUrl('ace/theme/chrome', themeChromeUrl)
ace.config.setModuleUrl('ace/theme/monokai', themeMonokaiUrl)
@@ -59,5 +64,6 @@ ace.config.setModuleUrl('ace/snippets/javascript', snippetsJsUrl)
ace.config.setModuleUrl('ace/snippets/javascript', snippetsYamlUrl)
ace.config.setModuleUrl('ace/snippets/json', snippetsJsonUrl)
ace.config.setModuleUrl('ace/snippets/css', snippertsCssUrl)
ace.config.setModuleUrl('ace/snippets/python', snippetsPythonUrl)
ace.require('ace/ext/language_tools')

View File

@@ -21,6 +21,14 @@ function filtersChanged(value: string[]) {
emit('changed', props.pri, value)
}
// 清洗规则中的换行符和多余空格,并在前后添加空格
const cleanedRules = computed(() => {
return props.rules.map(rule => {
rule = rule ?? ''
return ` ${rule.replace(/[\r\n]/g, '').replace(/\s+/g, '')} `
})
})
// 过滤规则下拉框
const selectFilterOptions = ref<{ [key: string]: string }[]>([
{ title: '特效字幕', value: ' SPECSUB ' },
@@ -77,7 +85,7 @@ const selectFilterOptions = ref<{ [key: string]: string }[]>([
<VRow>
<VCol>
<VSelect
v-model="props.rules"
v-model="cleanedRules"
variant="underlined"
:items="selectFilterOptions"
chips

View File

@@ -150,55 +150,61 @@ const dropdownItems = ref([
<template>
<VCard :width="props.width" :height="props.height" @click="installPlugin" class="flex flex-col">
<div class="relative pa-3 text-center card-cover-blurred" :style="{ background: `${backgroundColor}` }">
<div class="me-n3 absolute top-0 right-3">
<IconBtn>
<VIcon icon="mdi-dots-vertical" class="text-white" />
<VMenu activator="parent" close-on-content-click>
<VList>
<VListItem
v-for="(item, i) in dropdownItems"
v-show="item.show"
:key="i"
variant="plain"
@click="item.props.click"
>
<template #prepend>
<VIcon :icon="item.props.prependIcon" />
</template>
<VListItemTitle v-text="item.title" />
</VListItem>
</VList>
</VMenu>
</IconBtn>
</div>
<VAvatar size="6rem">
<VImg
ref="imageRef"
:src="iconPath"
aspect-ratio="4/3"
cover
:class="{ shadow: isImageLoaded }"
@load="imageLoaded"
@error="imageLoadError = true"
/>
</VAvatar>
<div class="me-n3 absolute bottom-0 right-3">
<IconBtn>
<VIcon icon="mdi-dots-vertical" />
<VMenu activator="parent" close-on-content-click>
<VList>
<VListItem
v-for="(item, i) in dropdownItems"
v-show="item.show"
:key="i"
variant="plain"
@click="item.props.click"
>
<template #prepend>
<VIcon :icon="item.props.prependIcon" />
</template>
<VListItemTitle v-text="item.title" />
</VListItem>
</VList>
</VMenu>
</IconBtn>
</div>
<VCardTitle>
{{ props.plugin?.plugin_name }}
<span class="text-sm text-gray-500">v{{ props.plugin?.plugin_version }}</span>
</VCardTitle>
<VCardText class="pb-2">
<div>{{ props.plugin?.plugin_desc }}</div>
<div>
<VChip v-for="label in pluginLabels" variant="tonal" size="small" class="me-1 my-1" color="info" label>
{{ label }}
</VChip>
<div
class="relative flex flex-row items-start pa-3 justify-between grow"
:style="{ background: `${backgroundColor}` }"
>
<div
class="absolute inset-0 bg-cover bg-center"
:style="{ background: `${backgroundColor}`, filter: 'brightness(0.7)' }"
></div>
<div class="relative flex-1 min-w-0">
<VCardTitle class="text-white px-2 text-shadow whitespace-nowrap overflow-hidden text-ellipsis">
{{ props.plugin?.plugin_name }}
<span class="text-sm text-gray-200">v{{ props.plugin?.plugin_version }}</span>
</VCardTitle>
<VCardText class="text-white px-2 py-1 text-shadow line-clamp-3">
{{ props.plugin?.plugin_desc }}
</VCardText>
</div>
</VCardText>
<VCardText class="flex align-self-baseline pb-2 w-full align-end">
<div class="relative flex-shrink-0 self-center">
<VAvatar size="64">
<VImg
ref="imageRef"
:src="iconPath"
aspect-ratio="4/3"
cover
:class="{ shadow: isImageLoaded }"
@load="imageLoaded"
@error="imageLoadError = true"
/>
</VAvatar>
</div>
</div>
<VCardText class="flex flex-none align-self-baseline py-3 w-full align-end">
<span>
<VIcon icon="mdi-account" class="me-1" />
<VIcon icon="mdi-github" class="me-1" />
<a :href="props.plugin?.author_url" target="_blank" @click.stop>
{{ props.plugin?.plugin_author }}
</a>
@@ -220,15 +226,3 @@ const dropdownItems = ref([
</VCard>
</VDialog>
</template>
<style lang="scss" scoped>
.card-cover-blurred::before {
position: absolute;
/* stylelint-disable-next-line property-no-vendor-prefix */
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
background: rgba(29, 39, 59, 48%);
content: '';
inset: 0;
}
</style>

View File

@@ -383,60 +383,75 @@ watch(
<template>
<!-- 插件卡片 -->
<VCard v-if="isVisible" :width="props.width" :height="props.height" @click="openPluginDetail" class="flex flex-col">
<div class="relative pa-3 text-center card-cover-blurred" :style="{ background: `${backgroundColor}` }">
<div v-if="props.plugin?.has_update" class="me-n3 absolute top-0 left-1">
<VIcon icon="mdi-new-box" class="text-white" />
</div>
<div class="me-n3 absolute top-0 right-3">
<IconBtn>
<VIcon icon="mdi-dots-vertical" class="text-white" />
<VMenu activator="parent" close-on-content-click>
<VList>
<VListItem
v-for="(item, i) in dropdownItems"
v-show="item.show"
:key="i"
variant="plain"
:base-color="item.props.color"
@click="item.props.click"
>
<template #prepend>
<VIcon :icon="item.props.prependIcon" />
</template>
<VListItemTitle v-text="item.title" />
</VListItem>
</VList>
</VMenu>
</IconBtn>
</div>
<VAvatar size="6rem">
<VImg
ref="imageRef"
:src="iconPath"
aspect-ratio="4/3"
cover
:class="{ shadow: isImageLoaded }"
@load="imageLoaded"
@error="imageLoadError = true"
/>
</VAvatar>
<div class="me-n3 absolute bottom-0 right-3">
<IconBtn>
<VIcon icon="mdi-dots-vertical" />
<VMenu activator="parent" close-on-content-click>
<VList>
<VListItem
v-for="(item, i) in dropdownItems"
v-show="item.show"
:key="i"
variant="plain"
:base-color="item.props.color"
@click="item.props.click"
>
<template #prepend>
<VIcon :icon="item.props.prependIcon" />
</template>
<VListItemTitle v-text="item.title" />
</VListItem>
</VList>
</VMenu>
</IconBtn>
</div>
<VCardItem class="py-2">
<VCardTitle class="flex items-center flex-row">
<VBadge v-if="props.plugin?.state" dot inline color="success" class="me-1 mb-1" />
{{ props.plugin?.plugin_name }}
<span class="text-sm ms-2 mt-1 text-gray-500">v{{ props.plugin?.plugin_version }}</span>
</VCardTitle>
</VCardItem>
<VCardText class="pb-1">
{{ props.plugin?.plugin_desc }}
</VCardText>
<VCardText class="flex justify-end align-self-baseline p-1 w-full align-end">
<div
class="relative flex flex-row items-start pa-3 justify-between grow"
:style="{ background: `${backgroundColor}` }"
>
<div
class="absolute inset-0 bg-cover bg-center"
:style="{ background: `${backgroundColor}`, filter: 'brightness(0.7)' }"
/>
<div class="relative flex-1 min-w-0">
<VCardTitle class="text-white px-2 text-shadow whitespace-nowrap overflow-hidden text-ellipsis">
<VBadge v-if="props.plugin?.state" dot inline color="success" />
{{ props.plugin?.plugin_name }}
<span class="text-sm mt-1 text-gray-200">v{{ props.plugin?.plugin_version }}</span>
</VCardTitle>
<VCardText class="px-2 py-1 text-white text-shadow line-clamp-3">
{{ props.plugin?.plugin_desc }}
</VCardText>
</div>
<div class="relative flex-shrink-0 self-center">
<VAvatar size="64">
<VImg
ref="imageRef"
:src="iconPath"
aspect-ratio="4/3"
cover
:class="{ shadow: isImageLoaded }"
@load="imageLoaded"
@error="imageLoadError = true"
/>
</VAvatar>
</div>
</div>
<VCardText class="flex flex-none align-self-baseline py-3 w-full align-end">
<span>
<VIcon icon="mdi-github" class="me-1" />
<a :href="props.plugin?.author_url" target="_blank" @click.stop>
{{ props.plugin?.plugin_author }}
</a>
</span>
<span v-if="props.count" class="ms-3">
<VIcon icon="mdi-fire" />
<span class="text-sm ms-1">{{ props.count?.toLocaleString() }}</span>
<VIcon icon="mdi-download" />
<span class="text-sm ms-1 mt-1">{{ props.count?.toLocaleString() }}</span>
</span>
</VCardText>
<div v-if="props.plugin?.has_update" class="me-n3 absolute top-0 right-5">
<VIcon icon="mdi-new-box" class="text-white" />
</div>
</VCard>
<!-- 插件配置页面 -->

View File

@@ -223,9 +223,9 @@ watch(
<div class="absolute inset-0 subscribe-card-background"></div>
</VImg>
</template>
<div v-if="imageLoaded">
<div>
<VCardText class="flex items-center">
<div class="h-auto w-12 flex-shrink-0 overflow-hidden rounded-md shadow-lg">
<div class="h-auto w-12 flex-shrink-0 overflow-hidden rounded-md shadow-lg" v-if="imageLoaded">
<VImg :src="props.media?.poster" aspect-ratio="2/3" cover @click.stop="viewMediaDetail">
<template #placeholder>
<div class="w-full h-full">

View File

@@ -8,7 +8,6 @@ const props = defineProps({
root: {
type: String,
default: '/',
required: true,
},
})

View File

@@ -2,6 +2,7 @@
import * as Mousetrap from 'mousetrap'
import SearchBarView from '@/views/system/SearchBarView.vue'
import { useDisplay } from 'vuetify'
import { ref, computed } from 'vue'
const display = useDisplay()
@@ -15,6 +16,14 @@ function openSearchDialog() {
searchDialog.value = true
return false
}
// 检测操作系统是否是Mac
function isMac() {
return navigator.platform.toUpperCase().indexOf('MAC') >= 0
}
// 计算属性:根据操作系统显示不同的按键提示
const metaKey = computed(() => (isMac() ? '⌘+K' : 'Ctrl+K'))
</script>
<template>
@@ -25,12 +34,13 @@ function openSearchDialog() {
</IconBtn>
<span v-if="display.lgAndUp.value" class="flex align-center text-disabled ms-2" @click="openSearchDialog">
<span class="me-3">搜索</span>
<span class="meta-key">K</span>
<span class="meta-key">{{ metaKey }}</span>
</span>
</div>
<!-- 搜索弹窗 -->
<SearchBarView v-model="searchDialog" v-if="searchDialog" @close="searchDialog = false" />
</template>
<style type="scss" scoped>
.meta-key {
border: thin solid rgba(var(--v-border-color), var(--v-border-opacity));
@@ -39,4 +49,4 @@ function openSearchDialog() {
padding-block: 0.1rem;
padding-inline: 0.25rem;
}
</style>
</style>

View File

@@ -32,8 +32,10 @@ function jumpTab(tab: string) {
@click="jumpTab(item.tab)"
selected-class="v-slide-group-item--active v-tab--selected"
>
<VIcon size="20" start :icon="item.icon" />
{{ item.title }}
<div>
<VIcon size="20" start :icon="item.icon" />
{{ item.title }}
</div>
</VTab>
</VTabs>
@@ -41,70 +43,90 @@ function jumpTab(tab: string) {
<!-- 用户 -->
<VWindowItem value="account">
<transition name="fade-slide" appear>
<AccountSettingAccount />
<div>
<AccountSettingAccount />
</div>
</transition>
</VWindowItem>
<!-- 连接 -->
<VWindowItem value="system">
<transition name="fade-slide" appear>
<AccountSettingSystem />
<div>
<AccountSettingSystem />
</div>
</transition>
</VWindowItem>
<!-- 目录 -->
<VWindowItem value="directory">
<transition name="fade-slide" appear>
<AccountSettingDirectory />
<div>
<AccountSettingDirectory />
</div>
</transition>
</VWindowItem>
<!-- 站点 -->
<VWindowItem value="site">
<transition name="fade-slide" appear>
<AccountSettingSite />
<div>
<AccountSettingSite />
</div>
</transition>
</VWindowItem>
<!-- 搜索 -->
<VWindowItem value="search">
<transition name="fade-slide" appear>
<AccountSettingSearch />
<div>
<AccountSettingSearch />
</div>
</transition>
</VWindowItem>
<!-- 订阅 -->
<VWindowItem value="subscribe">
<transition name="fade-slide" appear>
<AccountSettingSubscribe />
<div>
<AccountSettingSubscribe />
</div>
</transition>
</VWindowItem>
<!-- 服务 -->
<VWindowItem value="service">
<transition name="fade-slide" appear>
<AccountSettingService />
<div>
<AccountSettingService />
</div>
</transition>
</VWindowItem>
<!-- 通知 -->
<VWindowItem value="notification">
<transition name="fade-slide" appear>
<AccountSettingNotification />
<div>
<AccountSettingNotification />
</div>
</transition>
</VWindowItem>
<!-- 词表 -->
<VWindowItem value="words">
<transition name="fade-slide" appear>
<AccountSettingWords />
<div>
<AccountSettingWords />
</div>
</transition>
</VWindowItem>
<!-- 关于 -->
<VWindowItem value="about">
<transition name="fade-slide" appear>
<AccountSettingAbout />
<div>
<AccountSettingAbout />
</div>
</transition>
</VWindowItem>
</VWindow>

View File

@@ -156,7 +156,7 @@
}
.grid-plugin-card {
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
padding-block-end: 1rem;
}

View File

@@ -80,7 +80,13 @@ const options = controlledComputed(
fontSize: '12px',
},
formatter: (value: number) => (value > 999 ? (value / 1000).toFixed(0) : value),
formatter: (value: number) => {
if (value > 999) {
return (value / 1000).toFixed(1) + 'k'
} else {
return value.toString()
}
},
},
},
}

View File

@@ -347,7 +347,7 @@ onBeforeMount(async () => {
<transition name="fade-slide" appear>
<div>
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
<div v-if="dataList.length > 0" class="grid gap-4 grid-plugin-card items-start">
<div v-if="dataList.length > 0" class="grid gap-4 grid-plugin-card">
<template v-for="(data, index) in dataList" :key="`${data.id}_v${data.plugin_version}`">
<PluginCard
:count="PluginStatistics[data.id || '0']"
@@ -417,7 +417,7 @@ onBeforeMount(async () => {
</VCol>
</VRow>
</div>
<div v-if="isAppMarketLoaded" class="grid gap-4 grid-plugin-card items-start">
<div v-if="isAppMarketLoaded" class="grid gap-4 grid-plugin-card">
<template v-for="(data, index) in sortedUninstalledList" :key="`${data.id}_v${data.plugin_version}`">
<PluginAppCard :plugin="data" :count="PluginStatistics[data.id || '0']" @install="pluginInstalled" />
</template>

View File

@@ -148,12 +148,19 @@ const totalPage = computed(() => {
// 切换页签和搜索词
watch(
[() => currentPage.value, () => itemsPerPage.value, () => search.value],
[() => currentPage.value, () => itemsPerPage.value],
debounce(async () => {
reloadPage()
}, 1000),
)
watch(
[() => search.value],
debounce(async () => {
reloadPage(true)
}, 1000),
)
// 获取订阅列表数据
async function fetchData(page = currentPage.value, count = itemsPerPage.value) {
loading.value = true
@@ -335,7 +342,7 @@ function addUrlQuery(url: string, name: string, value: any) {
}
// 重载页面
function reloadPage() {
function reloadPage(resetPage = false) {
let url = '/history'
if (search.value) {
url = addUrlQuery(url, 'search', search.value)
@@ -344,7 +351,7 @@ function reloadPage() {
url = addUrlQuery(url, 'itemsPerPage', itemsPerPage.value)
}
if (currentPage.value) {
url = addUrlQuery(url, 'currentPage', currentPage.value)
url = addUrlQuery(url, 'currentPage', resetPage ? 1 : currentPage.value)
}
router.push(url)
}

View File

@@ -137,7 +137,7 @@ function addDownloadDirectory() {
downloadDirectories.value.push({
name: `下载目录${downloadDirectories.value.length + 1}`,
path: '',
media_type: '全部',
media_type: '',
category: '',
})
}
@@ -181,7 +181,7 @@ function addLibraryDirectory() {
libraryDirectories.value.push({
name: `媒体库目录${libraryDirectories.value.length + 1}`,
path: '',
media_type: '全部',
media_type: '',
category: '',
scrape: true,
})