Compare commits

..

21 Commits

Author SHA1 Message Date
jxxghp
236440be52 fix form 2024-02-27 15:23:07 +08:00
jxxghp
6f7e4bb272 release 2024-02-26 13:21:37 +08:00
jxxghp
38dcd3635a fix text 2024-02-25 17:17:53 +08:00
jxxghp
a3f3330dad fix 2024-02-25 08:58:46 +08:00
jxxghp
bbc6c57c08 Merge pull request #77 from cikezhu/main 2024-02-24 06:47:02 +08:00
叮叮当
2f36a8edef fix 2024-02-23 22:27:01 +08:00
叮叮当
df637fb887 定时作业添加提供者条目 2024-02-23 22:26:16 +08:00
jxxghp
be74c92a35 更新 package.json 2024-02-23 16:22:57 +08:00
jxxghp
a219a64e20 Merge pull request #76 from alkalixin/main 2024-02-23 16:22:19 +08:00
alkalixin
25c22a276a 给部分按钮增加浮动提示 2024-02-23 15:07:01 +08:00
jxxghp
6e6be057ca fix ui 2024-02-23 10:45:21 +08:00
jxxghp
af69efa48b feat:插件日志单独查看 2024-02-22 13:32:23 +08:00
jxxghp
c551083fa4 优化插件页面加载速度 2024-02-21 17:50:02 +08:00
jxxghp
9767feed29 更新 package.json 2024-02-18 15:19:52 +08:00
jxxghp
4392818e92 Merge pull request #75 from honue/main 2024-02-18 15:17:53 +08:00
honue
8d22bafeb6 订阅卡片增加剧集详情跳转功能 2024-02-18 15:08:22 +08:00
jxxghp
89ddd1fb78 更新 package.json 2024-02-17 13:19:04 +08:00
jxxghp
24513fa22b Merge pull request #74 from honue/main 2024-02-17 13:18:46 +08:00
honue
cddde0c2a0 fix 2024-02-17 13:09:48 +08:00
jxxghp
9c674e0018 更新 package.json 2024-02-15 21:06:19 +08:00
jxxghp
0c6476d283 更新 AccountSettingSystem.vue 2024-02-15 21:05:58 +08:00
13 changed files with 236 additions and 84 deletions

View File

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

View File

@@ -121,7 +121,11 @@ function themeTransition() {
<template>
<IconBtn @click="changeTheme">
<VIcon :icon="props.themes[currentThemeIndex].icon" />
<VTooltip text="切换主题">
<template #activator="{ props: _props }">
<VIcon v-bind="_props" :icon="props.themes[currentThemeIndex].icon" />
</template>
</VTooltip>
</IconBtn>
</template>

View File

@@ -877,6 +877,9 @@ export interface ScheduleInfo {
// 名称
name: string
// 提供者
provider: string
// 状态
status: string

View File

@@ -8,6 +8,7 @@ import PageRender from '@/components/render/PageRender.vue'
import { isNullOrEmptyObject } from '@core/utils'
import noImage from '@images/logos/plugin.png'
import { getDominantColor } from '@/@core/utils/image'
import store from '@/store'
// 输入参数
const props = defineProps({
@@ -225,6 +226,13 @@ function visitAuthorPage() {
window.open(props.plugin?.author_url, '_blank')
}
// 查看日志URL
function openLoggerWindow() {
const token = store.state.auth.token
const url = `${import.meta.env.VITE_API_BASE_URL}system/logging?token=${token}&length=-1&logfile=plugins/${props.plugin?.id?.toLowerCase()}.log`
window.open(url, '_blank')
}
// 弹出菜单
const dropdownItems = ref([
{
@@ -265,9 +273,20 @@ const dropdownItems = ref([
click: uninstallPlugin,
},
},
{
title: '查看日志',
value: 5,
show: true,
props: {
prependIcon: 'mdi-file-document-outline',
click: () => {
openLoggerWindow()
},
},
},
{
title: '作者主页',
value: 4,
value: 5,
show: true,
props: {
prependIcon: 'mdi-home-circle-outline',

View File

@@ -1,10 +1,11 @@
<script lang="ts" setup>
<script lang='ts' setup>
import { useToast } from 'vue-toast-notification'
import SubscribeEditForm from '../form/SubscribeEditForm.vue'
import { calculateTimeDifference } from '@/@core/utils'
import { formatSeason } from '@/@core/utils/formatters'
import api from '@/api'
import type { Subscribe } from '@/api/types'
import router from '@/router'
// 输入参数
const props = defineProps({
@@ -55,7 +56,7 @@ function getPercentage() {
return Math.round(
(((props.media?.total_episode ?? 0) - (props.media?.lack_episode ?? 0))
/ (props.media?.total_episode ?? 1))
* 100,
* 100,
)
}
@@ -126,8 +127,28 @@ const dropdownItems = ref([
},
},
{
title: '取消订阅',
title: '查看详情',
value: 3,
props: {
prependIcon: 'mdi-open-in-new',
click: () => {
router.push({
path: '/media',
query: {
mediaid: `${
props.media?.tmdbid
? `tmdb:${props.media?.tmdbid}`
: `douban:${props.media?.doubanid}`
}`,
type: props.media?.type,
},
})
},
},
},
{
title: '取消订阅',
value: 4,
props: {
prependIcon: 'mdi-trash-can-outline',
color: 'error',
@@ -162,7 +183,7 @@ const dropdownItems = ref([
</template>
<VCardTitle :class="getTextClass()">
{{ props.media?.name }}
{{ formatSeason(props.media?.season ? props.media?.season.toString() : "") }}
{{ formatSeason(props.media?.season ? props.media?.season.toString() : '') }}
</VCardTitle>
<template #append>
<div class="me-n3">
@@ -252,7 +273,8 @@ const dropdownItems = ref([
<VIcon
icon="mdi-download"
class="me-1"
/> {{ lastUpdateText }}
/>
{{ lastUpdateText }}
</VCardText>
<VProgressLinear
v-if="getPercentage() > 0"

View File

@@ -416,21 +416,41 @@ onMounted(() => {
</VMenu>
</IconBtn>
<span v-show="hover.isHovering" class="flex">
<IconBtn class="d-none d-sm-block" @click.stop="recognize(item.path)">
<VIcon icon="mdi-text-recognition" />
</IconBtn>
<IconBtn class="d-none d-sm-block" @click.stop="scrape(item.path)">
<VIcon icon="mdi-auto-fix" />
</IconBtn>
<IconBtn class="d-none d-sm-block" @click.stop="showRenmae(item)">
<VIcon icon="mdi-rename" />
</IconBtn>
<IconBtn class="d-none d-sm-block" @click.stop="showTransfer(item)">
<VIcon icon="mdi-folder-arrow-right" />
</IconBtn>
<IconBtn class="d-none d-sm-block" @click.stop="deleteItem(item)">
<VIcon icon="mdi-delete-outline" />
</IconBtn>
<VTooltip text="识别">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="recognize(item.path)">
<VIcon icon="mdi-text-recognition" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="刮削">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="scrape(item.path)">
<VIcon icon="mdi-auto-fix" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="重命名">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="showRenmae(item)">
<VIcon icon="mdi-rename" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="整理">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="showTransfer(item)">
<VIcon icon="mdi-folder-arrow-right" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="删除">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="deleteItem(item)">
<VIcon icon="mdi-delete-outline" color="error" />
</IconBtn>
</template>
</VTooltip>
</span>
</template>
</VListItem>
@@ -483,21 +503,41 @@ onMounted(() => {
</VMenu>
</IconBtn>
<span v-show="hover.isHovering" class="flex">
<IconBtn class="d-none d-sm-block" @click.stop="recognize(item.path)">
<VIcon icon="mdi-text-recognition" />
</IconBtn>
<IconBtn class="d-none d-sm-block" @click.stop="scrape(item.path)">
<VIcon icon="mdi-auto-fix" />
</IconBtn>
<IconBtn class="d-none d-sm-block" @click.stop="showRenmae(item)">
<VIcon icon="mdi-rename" />
</IconBtn>
<IconBtn class="d-none d-sm-block" @click.stop="showTransfer(item)">
<VIcon icon="mdi-folder-arrow-right" />
</IconBtn>
<IconBtn class="d-none d-sm-block" @click.stop="deleteItem(item)">
<VIcon icon="mdi-delete-outline" />
</IconBtn>
<VTooltip text="识别">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="recognize(item.path)">
<VIcon icon="mdi-text-recognition" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="刮削">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="scrape(item.path)">
<VIcon icon="mdi-auto-fix" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="重命名">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="showRenmae(item)">
<VIcon icon="mdi-rename" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="整理">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="showTransfer(item)">
<VIcon icon="mdi-folder-arrow-right" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="删除">
<template #activator="{ props }">
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="deleteItem(item)">
<VIcon icon="mdi-delete-outline" color="error" />
</IconBtn>
</template>
</VTooltip>
</span>
</template>
</VListItem>

View File

@@ -144,19 +144,31 @@ const sortIcon = computed(() => {
</template>
</VToolbarItems>
<div class="flex-grow-1" />
<IconBtn @click="changeSort">
<VIcon :icon="sortIcon" />
</IconBtn>
<IconBtn v-if="pathSegments.length > 0" @click="goUp">
<VIcon icon="mdi-arrow-up-bold-outline" />
</IconBtn>
<VTooltip text="调整排序">
<template #activator="{ props }">
<IconBtn v-bind="props" @click="changeSort">
<VIcon :icon="sortIcon" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="返回上一级" v-if="pathSegments.length > 0">
<template #activator="{ props }">
<IconBtn v-bind="props" @click="goUp">
<VIcon icon="mdi-arrow-up-bold-outline" />
</IconBtn>
</template>
</VTooltip>
<VDialog
v-model="newFolderPopper"
max-width="50rem"
>
<template #activator="{ props }">
<IconBtn title="新建文件夹" v-bind="props">
<VIcon icon="mdi-folder-plus-outline" />
<IconBtn v-bind="props">
<VTooltip text="新建文件夹">
<template #activator="{ props: _props }">
<VIcon v-bind="_props" icon="mdi-folder-plus-outline" />
</template>
</VTooltip>
</IconBtn>
</template>
<VCard title="新建文件夹">

View File

@@ -44,7 +44,11 @@ function allLoggingUrl() {
class="me-2"
v-bind="props"
>
<VIcon icon="mdi-checkbox-multiple-blank-outline" />
<VTooltip text="捷径">
<template #activator="{ props: _props }">
<VIcon v-bind="_props" icon="mdi-checkbox-multiple-blank-outline" />
</template>
</VTooltip>
</IconBtn>
</template>
<!-- Menu Content -->

View File

@@ -5,25 +5,21 @@ import NoDataFound from '@/components/NoDataFound.vue'
import PluginAppCard from '@/components/cards/PluginAppCard.vue'
import PluginCard from '@/components/cards/PluginCard.vue'
// 数据列表
// 已安装插件列表
const dataList = ref<Plugin[]>([])
// 未安装插件列表
const uninstalledList = ref<Plugin[]>([])
// 是否刷新过
const isRefreshed = ref(false)
// APP市场是否加载完成
const isAppMarketLoaded = ref(false)
// APP市场窗口
const PluginAppDialog = ref(false)
// 获取已安装的插件列表
const getInstalledPluginList = computed(() => {
return dataList.value.filter(item => item.installed)
})
// 获取未安装或者有更新的插件列表
const getUninstalledPluginList = computed(() => {
return dataList.value.filter(item => !item.installed || item.has_update)
})
// 关闭插件市场窗口
function pluginDialogClose() {
PluginAppDialog.value = false
@@ -31,14 +27,19 @@ function pluginDialogClose() {
// 新安装了插件
function pluginInstalled() {
fetchData()
fetchInstalledPlugins()
pluginDialogClose()
fetchUninstalledPlugins()
}
// 获取插件列表数据
async function fetchData() {
async function fetchInstalledPlugins() {
try {
dataList.value = await api.get('plugin/')
dataList.value = await api.get('plugin/', {
params: {
state: 'installed',
},
})
isRefreshed.value = true
}
catch (error) {
@@ -46,8 +47,26 @@ async function fetchData() {
}
}
// 获取未安装插件列表数据
async function fetchUninstalledPlugins() {
try {
uninstalledList.value = await api.get('plugin/', {
params: {
state: 'market',
},
})
isAppMarketLoaded.value = true
}
catch (error) {
console.error(error)
}
}
// 加载时获取数据
onBeforeMount(fetchData)
onBeforeMount(() => {
fetchInstalledPlugins()
fetchUninstalledPlugins()
})
</script>
<template>
@@ -63,19 +82,19 @@ onBeforeMount(fetchData)
/>
</div>
<div
v-if="getInstalledPluginList.length > 0"
v-if="dataList.length > 0"
class="grid gap-4 grid-plugin-card"
>
<PluginCard
v-for="data in getInstalledPluginList"
v-for="data in dataList"
:key="data.id"
:plugin="data"
@remove="fetchData"
@save="fetchData"
@remove="fetchInstalledPlugins"
@save="fetchInstalledPlugins"
/>
</div>
<NoDataFound
v-if="getInstalledPluginList.length === 0 && isRefreshed"
v-if="dataList.length === 0 && isRefreshed"
error-code="404"
error-title="没有安装插件"
error-description="点击右下角按钮前往插件市场安装插件"
@@ -121,16 +140,27 @@ onBeforeMount(fetchData)
</VToolbar>
</div>
<VCardText>
<div class="grid gap-4 grid-plugin-card">
<div
v-if="!isAppMarketLoaded"
class="mt-12 w-full text-center text-gray-500 text-sm flex flex-col items-center"
>
<VProgressCircular
v-if="!isAppMarketLoaded"
size="48"
indeterminate
color="primary"
/>
</div>
<div v-if="isAppMarketLoaded" class="grid gap-4 grid-plugin-card">
<PluginAppCard
v-for="data in getUninstalledPluginList"
v-for="data in uninstalledList"
:key="data.id"
:plugin="data"
@install="pluginInstalled"
/>
</div>
<NoDataFound
v-if="getUninstalledPluginList.length === 0 && isRefreshed"
v-if="uninstalledList.length === 0 && isAppMarketLoaded"
error-code="404"
error-title="没有未安装插件"
error-description="所有可用插件均已安装"

View File

@@ -357,7 +357,7 @@ const dropdownItems = ref([
<VIcon :icon="getIcon(item.value.type || '')" />
</VAvatar>
<div class="d-flex flex-column ms-1">
<span class="d-block whitespace-nowrap text-high-emphasis">
<span class="d-block text-high-emphasis">
{{ item.value.title }} {{ item.value.seasons }}{{ item.value.episodes }}
</span>
<small>{{ item.value.category }}</small>
@@ -415,8 +415,16 @@ const dropdownItems = ref([
</VCard>
<!-- 底部操作按钮 -->
<span v-if="selected.length > 0" class="fixed right-5 bottom-5">
<VBtn icon="mdi-redo-variant" class="me-2" color="primary" size="x-large" @click="retransferBatch" />
<VBtn icon="mdi-trash-can-outline" color="error" size="x-large" @click="removeHistoryBatch" />
<VTooltip text="批量重新整理">
<template #activator="{ props }">
<VBtn v-bind="props" icon="mdi-redo-variant" class="me-2" color="primary" size="x-large" @click="retransferBatch" />
</template>
</VTooltip>
<VTooltip text="批量删除">
<template #activator="{ props }">
<VBtn v-bind="props" icon="mdi-trash-can-outline" color="error" size="x-large" @click="removeHistoryBatch" />
</template>
</VTooltip>
</span>
<!-- 底部弹窗 -->
<VBottomSheet v-model="deleteConfirmDialog" inset>

View File

@@ -78,11 +78,14 @@ onUnmounted(() => {
<template>
<VCard title="定时作业">
<VCardSubtitle> 手动执行不会影响作业正常的时间表 </VCardSubtitle>
<VCardSubtitle> 包含系统内置服务以及插件提供的服务手动执行不会影响作业正常的时间表 </VCardSubtitle>
<VTable class="text-no-wrap">
<thead>
<tr>
<th scope="col">
提供者
</th>
<th scope="col">
任务名称
</th>
@@ -100,6 +103,9 @@ onUnmounted(() => {
v-for="scheduler in schedulerList"
:key="scheduler.id"
>
<td>
{{ scheduler.provider }}
</td>
<td>
{{ scheduler.name }}
</td>

View File

@@ -1,4 +1,4 @@
<script lang="ts" setup>
<script lang='ts' setup>
import { useToast } from 'vue-toast-notification'
import api from '@/api'
import FilterRuleCard from '@/components/cards/FilterRuleCard.vue'
@@ -94,7 +94,7 @@ async function saveSelectedRssSites() {
const result2: { [key: string]: any } = await api.post(
'system/setting/SUBSCRIBE_SEARCH',
enableIntervalSearch.value,
enableIntervalSearch.value ? 'True' : 'False',
)
const result3: { [key: string]: any } = await api.post(
@@ -469,7 +469,7 @@ onMounted(() => {
</VMenu>
</IconBtn>
</template>
<VCardSubtitle> 设置在正常订阅时默认使用的优先级未在优先级中的资源将不会自动下载 </VCardSubtitle>
<VCardSubtitle> 设置在正常订阅时默认使用的优先级未在优先级中的资源将不会自动下载</VCardSubtitle>
<VCardItem>
<div class="grid gap-3 grid-filterrule-card">
<FilterRuleCard
@@ -535,7 +535,7 @@ onMounted(() => {
</VMenu>
</IconBtn>
</template>
<VCardSubtitle> 设置在订阅洗版时使用的优先级匹配优先级1时洗版完成 </VCardSubtitle>
<VCardSubtitle> 设置在订阅洗版时使用的优先级匹配优先级1时洗版完成</VCardSubtitle>
<VCardItem>
<div class="grid gap-3 grid-filterrule-card">
<FilterRuleCard
@@ -571,7 +571,7 @@ onMounted(() => {
</VCol>
<VCol cols="12">
<VCard title="默认过滤规则">
<VCardSubtitle> 设置在订阅时默认使用的过滤规则 </VCardSubtitle>
<VCardSubtitle> 设置在订阅时默认使用的过滤规则</VCardSubtitle>
<VCardText>
<VForm>
<VRow>
@@ -638,7 +638,7 @@ onMounted(() => {
</VDialog>
</template>
<style lang="scss">
<style lang='scss'>
.grid-filterrule-card {
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
padding-block-end: 1rem;

View File

@@ -3,6 +3,7 @@
import { useToast } from 'vue-toast-notification'
import { VRow } from 'vuetify/lib/components/index.mjs'
import api from '@/api'
import { requiredValidator } from '@/@validators'
// 选中的媒体服务器
const selectedMediaServers = ref([])
@@ -532,8 +533,8 @@ onMounted(() => {
<VCol cols="12" md="4">
<VTextField
v-model="mediaServerSettings.EMBY_PLAY_HOST"
label="播放地址"
placeholder="IP:PORT"
label="外网播放地址"
placeholder="http(s)://domain:port"
/>
</VCol>
<VCol cols="12" md="4">
@@ -559,7 +560,7 @@ onMounted(() => {
<VTextField
v-model="mediaServerSettings.JELLYFIN_PLAY_HOST"
label="外网播放地址"
placeholder="IP:PORT"
placeholder="http(s)://domain:port"
/>
</VCol>
<VCol cols="12" md="4">
@@ -585,7 +586,7 @@ onMounted(() => {
<VTextField
v-model="mediaServerSettings.PLEX_PLAY_HOST"
label="外网播放地址"
placeholder="IP:PORT"
placeholder="http(s)://domain:port"
/>
</VCol>
<VCol cols="12" md="4">
@@ -628,6 +629,7 @@ onMounted(() => {
<VTextField
v-model="mediaSettings.DOWNLOAD_PATH"
label="下载目录"
:rules="[requiredValidator]"
/>
</VCol>
<VCol cols="12" md="6">
@@ -682,6 +684,8 @@ onMounted(() => {
<VTextField
v-model="mediaSettings.LIBRARY_PATH"
label="媒体库目录"
placeholder="多个目录使用,分隔"
:rules="[requiredValidator]"
/>
</VCol>
<VCol cols="12" md="6">