Compare commits

..

77 Commits

Author SHA1 Message Date
jxxghp
b6fcee517d fix 2023-12-23 18:59:43 +08:00
jxxghp
4f62551f6b fix 历史记录路径 2023-12-16 12:10:30 +08:00
jxxghp
3980249271 Merge branch 'main' of https://github.com/jxxghp/MoviePilot-Frontend 2023-12-14 07:10:56 +08:00
jxxghp
e3b11b1130 fix 整理默认路径 2023-12-14 07:08:39 +08:00
jxxghp
f866f23af1 Merge pull request #62 from thsrite/main 2023-12-14 06:30:15 +08:00
thsrite
c793bc24f0 feat 订阅增加保存路径设置 2023-12-12 14:01:35 +08:00
jxxghp
591a46d559 add icon 2023-12-10 13:40:27 +08:00
jxxghp
2852f26702 fix 站点限流设置Bug 2023-12-07 15:44:01 +08:00
jxxghp
fc818fdfd6 v1.4.9 2023-12-06 10:24:43 +08:00
jxxghp
5566ef87f8 feat 插件跳转Github 2023-11-30 16:57:01 +08:00
jxxghp
366fe34d6f fix 2023-11-30 15:25:28 +08:00
jxxghp
37a0e83124 fix 规则导入 2023-11-30 15:18:10 +08:00
jxxghp
061a3f393a fix 2023-11-30 14:10:39 +08:00
jxxghp
1dff22aeab fix 2023-11-30 13:30:51 +08:00
jxxghp
78e6fd4809 fix clipboard 2023-11-30 12:58:25 +08:00
jxxghp
96bbf3d0f2 fix bug 2023-11-30 12:49:55 +08:00
jxxghp
a842eaba4e build 2023-11-30 11:59:52 +08:00
jxxghp
37565bf8e4 feat 优先级规则分享&导入 2023-11-30 11:59:26 +08:00
jxxghp
beb158b387 Merge pull request #59 from jjjokin/feat-history-search-hint 2023-11-29 12:33:03 +08:00
jokin
408eb06f8d feat 添加历史记录搜索提示 2023-11-29 12:17:02 +08:00
jxxghp
abe0e44635 fix typing 2023-11-29 12:08:13 +08:00
jxxghp
cfaf414f1c feat 自动计算图标颜色 2023-11-29 12:05:55 +08:00
jxxghp
f9c4dc616b fix 2023-11-29 09:27:39 +08:00
jxxghp
bf845bab6b feat 插件默认图标与背景色 2023-11-29 08:34:25 +08:00
jxxghp
bae9c85990 fix 2023-11-29 08:11:47 +08:00
jxxghp
56bbb8d0ff fix README.md 2023-11-28 15:08:11 +08:00
jxxghp
60d3565231 build icons 2023-11-28 10:15:24 +08:00
jxxghp
81340fd287 Merge branch 'main' of https://github.com/jxxghp/MoviePilot-Frontend 2023-11-27 08:27:51 +08:00
jxxghp
c10c348c73 feat 插件操作确认 2023-11-27 08:27:49 +08:00
jxxghp
65cb7d9674 更新 PluginAppCard.vue 2023-11-27 07:06:43 +08:00
jxxghp
24f1a10ff7 feat 插件重置 2023-11-26 21:40:27 +08:00
jxxghp
767d11182a add plugin icon 2023-11-26 20:07:13 +08:00
jxxghp
cf363f667e fix plugin ui 2023-11-24 09:56:05 +08:00
jxxghp
0d1046b8c7 v1.4.4 2023-11-20 19:55:52 +08:00
jxxghp
2c05f5779e v1.4.3 2023-11-19 13:49:16 +08:00
jxxghp
9af200f89e feat 支持更多豆瓣详情展示 2023-11-18 21:52:35 +08:00
jxxghp
7e221cfd46 fix douban check subscribe 2023-11-13 20:23:13 +08:00
jxxghp
640882d178 v1.4.2 2023-11-13 12:05:26 +08:00
jxxghp
3a1436abef fix #1100 2023-11-10 21:41:57 +08:00
jxxghp
d431f0490d fix user add 2023-11-10 20:41:01 +08:00
jxxghp
4c2a6c92a6 fix 2023-11-10 12:22:06 +08:00
jxxghp
086c230e9e fix text 2023-11-09 23:26:46 +08:00
jxxghp
27e2ff50f2 fix ui 2023-11-09 12:31:00 +08:00
jxxghp
3134e5596b fix 2023-11-07 09:57:46 +08:00
jxxghp
315274abf9 fix ui 2023-11-06 11:42:13 +08:00
jxxghp
52bbf65fa8 fix #1046 2023-11-05 21:45:42 +08:00
jxxghp
9c018ec63b Merge branch 'main' of https://github.com/jxxghp/MoviePilot-Frontend 2023-11-05 21:43:33 +08:00
jxxghp
bd7e457cdb fix ui 2023-11-05 21:43:27 +08:00
jxxghp
36a0f8515b 更新 package.json 2023-11-05 09:14:17 +08:00
jxxghp
cac10a337d fix 2023-11-04 22:27:56 +08:00
jxxghp
edb53cc58f fix plugin market icon 2023-11-02 12:50:57 +08:00
jxxghp
1dceeecdad fix ui 2023-11-02 11:16:38 +08:00
jxxghp
f8071ada0b feat 插件支持在线图标 2023-11-01 22:03:46 +08:00
jxxghp
21bc8edbd8 feat 在线插件市场 2023-11-01 21:05:31 +08:00
jxxghp
2a8aeb5041 feat 插件市场显示版本号 2023-11-01 18:02:51 +08:00
jxxghp
1a7760cf6d fix build 2023-11-01 17:05:12 +08:00
jxxghp
aee4eed5ac feat 拆分插件图标 2023-11-01 17:02:57 +08:00
jxxghp
87215fb590 add icons 2023-11-01 16:23:50 +08:00
jxxghp
5409126187 add versions 2023-11-01 12:23:08 +08:00
jxxghp
9840782ce5 v1.3.8 2023-10-31 11:48:17 +08:00
jxxghp
d18f42cd6f v1.3.7-1 2023-10-29 18:41:18 +08:00
jxxghp
9372e98459 fix #57 2023-10-29 18:40:37 +08:00
jxxghp
9400f4660d Merge pull request #57 from Shurelol/main 2023-10-29 17:53:05 +08:00
Shurelol
f0d66b8fba feat: 识别测试结果在应用识别词时显示应用详情 2023-10-28 02:56:08 +08:00
jxxghp
78abe72815 Merge pull request #56 from thsrite/main 2023-10-27 17:07:13 +08:00
thsrite
1ce75916ef fix 正在下载显示剩余下载时间 2023-10-27 16:53:09 +08:00
jxxghp
46959d4baa v1.3.7 2023-10-26 17:09:29 +08:00
jxxghp
b24cc44493 Merge pull request #55 from thsrite/main 2023-10-26 16:04:43 +08:00
thsrite
46f6c29e1d feat 云盘文件删除插件 2023-10-26 14:49:09 +08:00
thsrite
5ad75b8420 fix 登录页海报支持自定义tmdb/bing 2023-10-24 10:55:45 +08:00
jxxghp
2030459f20 v1.3.6-1 2023-10-22 08:23:43 +08:00
jxxghp
2855bf812b fix #947 2023-10-22 08:18:01 +08:00
jxxghp
69989893d9 v1.3.6 2023-10-21 14:22:49 +08:00
jxxghp
ffc61f4a31 Merge pull request #54 from thsrite/main 2023-10-20 14:33:15 +08:00
thsrite
dd051f28d2 feat 站点自动登录插件 2023-10-20 12:54:12 +08:00
jxxghp
a3d2def72b fix ui bug 2023-10-20 12:42:54 +08:00
jxxghp
e8552b4385 v1.3.5-1 2023-10-20 07:37:44 +08:00
84 changed files with 1416 additions and 117 deletions

View File

@@ -27,6 +27,13 @@ jobs:
node-version: '18'
cache: 'yarn'
- name: Download Icons
run: |
pwd
curl -sL "https://github.com/jxxghp/MoviePilot-Plugins/archive/refs/heads/main.zip" | busybox unzip -d /tmp -
mv /tmp/MoviePilot-Plugins-main/icons public/plugin_icon
rm -rf /tmp/MoviePilot-Plugins-main
- name: Build frontend
id: build_frontend
run: |

1
.gitignore vendored
View File

@@ -32,3 +32,4 @@ dist-ssr
# iconify dist files
src/@iconify/*.js
public/plugin_icon/**

View File

@@ -31,8 +31,8 @@
"volar.preview.port": 3000,
"volar.completion.preferredTagNameCase": "pascal",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll.stylelint": true
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
"eslint.alwaysShowStatus": true,
"eslint.format.enable": true,

View File

@@ -1,35 +1,39 @@
# MoviePilot-Frontend
This template should help get you started developing with Vue 3 in Vite.
[MoviePilot](https://github.com/jxxghp/MoviePilot) 的前端项目。
## Recommended IDE Setup
## 推荐的IDE设置
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (and disable Vetur).
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (并禁用 Vetur).
## Type Support for `.vue` Imports in TS
## 配置Vite
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates.
请参阅 [Vite 配置参考](https://vitejs.dev/config/).
However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can run `Volar: Switch TS Plugin on/off` from VSCode command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
## 依赖安装
```sh
yarn
```
### Compile and Hot-Reload for Development
### 开发运行
```sh
yarn dev
```
### Type-Check, Compile and Minify for Production
### 编译打包
```sh
yarn build
```
### 静态运行
1. 使用 `nginx` 等Web服务器托管 `dist` 静态文件nginx配置参考 `public/nginx.conf`
2. 使用 `node` 命令直接运行`service.js`,默认监听 `3000` 端口,设置环境变量 `NGINX_PORT` 来调整运行端口。
```shell
node dist/service.js
```

View File

@@ -1,6 +1,6 @@
{
"name": "moviepilot",
"version": "1.3.5",
"version": "1.5.3",
"private": true,
"bin": "dist/service.js",
"scripts": {
@@ -28,6 +28,7 @@
"axios": "1.4.0",
"axios-mock-adapter": "^1.21.4",
"chart.js": "^4.1.2",
"colorthief": "^2.4.0",
"express": "^4.18.2",
"express-http-proxy": "^2.0.0",
"jwt-decode": "^3.1.2",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -55,7 +55,7 @@ export function formatFileSize(bytes: number) {
if (bytes < 0)
throw new Error('字节数不能为负数。')
const units = ['B', 'K', 'M', 'G', 'T']
const units = ['B', 'KB', 'MB', 'GB', 'TB']
let size = bytes
let unitIndex = 0

23
src/@core/utils/image.ts Normal file
View File

@@ -0,0 +1,23 @@
import ColorThief from 'colorthief'
// 将 RGB 转换为十六进制
function rgbStringToHex(rgbArray: number[]): string {
if (rgbArray.length !== 3 || rgbArray.some(isNaN))
throw new Error('Invalid RGB string format')
const [r, g, b] = rgbArray
const toHex = (c: number): string => {
const hex = c.toString(16)
return hex.length === 1 ? `0${hex}` : hex
}
return `#${toHex(r)}${toHex(g)}${toHex(b)}`
}
// 提取主要颜色
export async function getDominantColor(image: HTMLImageElement): Promise<string> {
const colorThief = new ColorThief()
const dominantColor = colorThief.getColor(image)
return rgbStringToHex(dominantColor)
}

View File

@@ -0,0 +1,30 @@
// 请求和获取剪贴板内容
export async function getClipboardContent() {
if (navigator.clipboard && window.isSecureContext) {
return await navigator.clipboard.readText()
}
else {
const input = document.createElement('textarea')
document.body.appendChild(input)
input.select()
document.execCommand('paste')
const content = input.value
document.body.removeChild(input)
return content
}
}
// 将内容复制到剪贴板,兼容非安全域场景
export async function copyToClipboard(content: string) {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(content)
}
else {
const input = document.createElement('textarea')
input.value = content
document.body.appendChild(input)
input.select()
document.execCommand('copy')
document.body.removeChild(input)
}
}

View File

@@ -82,6 +82,9 @@ export interface Subscribe {
// 当前优先级
current_priority: number
// 保存目录
save_path: string
}
// 历史记录
@@ -337,7 +340,7 @@ export interface TmdbEpisode {
guest_stars: Object[]
}
// TMDB人信息
// TMDB人信息
export interface TmdbPerson {
// ID
id?: number
@@ -388,6 +391,34 @@ export interface TmdbPerson {
biography?: string
}
// 豆瓣人物信息
export interface DoubanPerson {
// ID
id?: string
// 名称
name?: string
// 角色
roles?: string[]
// 简介
title?: string
// 详情页面
url?: string
// 饰演
character?: string
// 图片 large/normal
avatar?: { [key: string]: string }
// 别名
latin_name?: string
}
// 站点
export interface Site {
@@ -512,9 +543,6 @@ export interface Plugin {
// 插件图标
plugin_icon?: string
// 主题色
plugin_color?: string
// 插件版本
plugin_version?: string
@@ -541,6 +569,15 @@ export interface Plugin {
// 是否有详情页面
has_page?: boolean
// 是否有新版本
has_update?: boolean
// 是否本地插件
is_local?: boolean
// 插件仓库地址
repo_url?: string
}
// 种子信息
@@ -625,6 +662,9 @@ export interface MetaInfo {
// 原字符串
org_string?: string
// 原标题(未经识别词转换)
title?: string
// 副标题
subtitle?: string
@@ -726,6 +766,9 @@ export interface MetaInfo {
// 资源类型+特效
edition: string
// 应用的自定义识别词
apply_words: string[]
}
// 上下文信息

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,88 @@
<script lang="ts" setup>
import personIcon from '@images/misc/person-icon.png'
import type { DoubanPerson } from '@/api/types'
const personProps = defineProps({
person: Object as PropType<DoubanPerson>,
width: String,
height: String,
})
// 当前人物
const personInfo = ref(personProps.person)
// 人物图片是否加载
const isImageLoaded = ref(false)
// 人物图片地址
function getPersonImage() {
if (!personInfo.value?.avatar)
return personIcon
return personInfo.value?.avatar?.large
}
// 打开人物详情
function goPersonDetail() {
if (!personInfo.value?.id)
return
window.open(`https://movie.douban.com/celebrity/${personInfo.value?.id}/`, '_blank')
}
</script>
<template>
<VHover v-bind="personProps">
<template #default="hover">
<VCard
v-bind="hover.props"
:height="personProps.height"
:width="personProps.width"
class="rounded-lg"
:class="{
'transition transform-cpu duration-300 scale-105': hover.isHovering,
}"
@click.stop="goPersonDetail"
>
<div
class="person-card relative transform-gpu cursor-pointer rounded shadow ring-1 transition duration-150 ease-in-out scale-100 ring-gray-700"
>
<div style="padding-bottom: 150%;">
<div class="absolute inset-0 flex h-full w-full flex-col items-center p-2">
<div class="relative mt-2 mb-4 flex h-1/2 w-full justify-center">
<VAvatar
size="120"
:class="{
'ring-1 ring-gray-700': isImageLoaded,
}"
>
<VImg
v-img
:src="getPersonImage()"
cover
@load="isImageLoaded = true"
/>
</VAvatar>
</div>
<div class="w-full truncate text-center font-bold">
{{ personInfo?.name }}
</div>
<div class="overflow-hidden whitespace-normal text-center text-sm" style=" display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical;-webkit-line-clamp: 2;">
{{ personInfo?.character }}
</div>
<div class="absolute bottom-0 left-0 right-0 h-12 rounded-b" />
</div>
</div>
</div>
</VCard>
</template>
</VHover>
</template>
<style lang="scss">
.person-card {
background-image: linear-gradient(45deg, rgb(var(--v-theme-background)), rgb(var(--v-theme-surface)) 60%);
}
.person-card:hover {
background-image: linear-gradient(45deg, rgb(var(--v-theme-background)), rgb(var(--v-custom-background)) 60%);
}
</style>

View File

@@ -17,7 +17,7 @@ function getPercentage() {
// 速度
function getSpeedText() {
return `${props.info?.upspeed}/s ↓ ${props.info?.dlspeed}/s`
return `${props.info?.upspeed}/s ↓ ${props.info?.dlspeed}/s ${props.info?.left_time}`
}
// 下载状态

View File

@@ -34,7 +34,7 @@ const isSubscribed = ref(false)
// 本地存在状态
const isExists = ref(false)
// 各季缺失状态0-已存在 1-部分缺失 2-全部缺失,没有数据也是已存在
// 各季缺失状态0-已入库 1-部分缺失 2-全部缺失,没有数据也是已入库
const seasonsNotExisted = ref<{ [key: number]: number }>({})
// 订阅季弹窗
@@ -44,7 +44,7 @@ const subscribeSeasonDialog = ref(false)
const subscribeEditDialog = ref(false)
// 订阅ID
const subscribeId = ref(0)
const subscribeId = ref<number>()
// 季详情
const seasonInfos = ref<TmdbSeason[]>([])
@@ -220,7 +220,7 @@ async function handleCheckSubscribe() {
}
}
// 查询当前媒体是否已存在
// 查询当前媒体是否已入库
async function handleCheckExists() {
try {
const result: { [key: string]: any } = await api.get('media/exists', {
@@ -251,6 +251,7 @@ async function checkSubscribe(season = 0) {
const result: Subscribe = await api.get(`subscribe/media/${mediaid}`, {
params: {
season,
title: props.media?.title,
},
})
@@ -271,7 +272,7 @@ async function checkSeasonsNotExists() {
const result: NotExistMediaInfo[] = await api.post('download/notexists', props.media)
if (result) {
result.forEach((item) => {
// 0-已存在 1-部分缺失 2-全部缺失
// 0-已入库 1-部分缺失 2-全部缺失
let state = 0
if (item.episodes.length === 0)
state = 2
@@ -327,14 +328,14 @@ function getExistColor(season: number) {
function getExistText(season: number) {
const state = seasonsNotExisted.value[season]
if (!state)
return '已存在'
return '已入库'
if (state === 1)
return '部分缺失'
else if (state === 2)
return '缺失'
else
return '已存在'
return '已入库'
}
// 打开详情页

View File

@@ -143,5 +143,33 @@ function openTmdbPage(type: string, tmdbId: number) {
识别失败无法识别到有效信息
</VAlert>
</VCol>
<VExpansionPanels
v-show="context?.meta_info?.title !== context?.meta_info.org_string"
>
<VExpansionPanel>
<VExpansionPanelTitle>
识别词应用详情
</VExpansionPanelTitle>
<VExpansionPanelText>
<VChip
variant="elevated"
class="me-1 mb-1 break-all"
color="primary"
>
{{ context?.meta_info.org_string }}
</VChip>
<VChip
v-for="(val, key) in context?.meta_info.apply_words"
:key="key"
:val="val"
variant="outlined"
color="info"
class="me-1 mb-1 break-all"
>
{{ val }}
</VChip>
</VExpansionPanelText>
</VExpansionPanel>
</VExpansionPanels>
</div>
</template>

View File

@@ -2,6 +2,8 @@
import { useToast } from 'vue-toast-notification'
import api from '@/api'
import type { Plugin } from '@/api/types'
import noImage from '@images/logos/plugin.png'
import { getDominantColor } from '@/@core/utils/image'
// 输入参数
const props = defineProps({
@@ -13,19 +15,55 @@ const props = defineProps({
// 定义触发的自定义事件
const emit = defineEmits(['install'])
// 背景颜色
const backgroundColor = ref('#28A9E1')
// 图片对象
const imageRef = ref<any>()
// 提示框
const $toast = useToast()
// 进度框
const progressDialog = ref(false)
// 进度框文本
const progressText = ref('正在安装插件...')
// 图片是否加载完成
const isImageLoaded = ref(false)
// 图片是否加载失败
const imageLoadError = ref(false)
// 图片加载完成
async function imageLoaded() {
isImageLoaded.value = true
const imageElement = imageRef.value?.$el.querySelector('img') as HTMLImageElement
// 从图片中提取背景色
backgroundColor.value = await getDominantColor(imageElement)
}
// 安装插件
async function installPlugin() {
try {
// 显示等待提示框
progressDialog.value = true
progressText.value = `正在安装 ${props.plugin?.plugin_name} ${props?.plugin?.plugin_version} 插件...`
const result: { [key: string]: any } = await api.get(
`plugin/install/${props.plugin?.id}`,
{
params: {
repo_url: props.plugin?.repo_url,
force: props.plugin?.has_update,
},
},
)
// 隐藏等待提示框
progressDialog.value = false
if (result.success) {
$toast.success(`插件 ${props.plugin?.plugin_name} 安装成功!`)
@@ -33,13 +71,63 @@ async function installPlugin() {
emit('install')
}
else {
$toast.error(`插件 ${props.plugin?.plugin_name} 安装失败:${result.message}}`)
$toast.error(`插件 ${props.plugin?.plugin_name} 安装失败:${result.message}`)
}
}
catch (error) {
console.error(error)
}
}
// 计算图标路径
const iconPath: Ref<string> = computed(() => {
if (imageLoadError.value)
return noImage
// 如果是网络图片则使用代理后返回
if (props.plugin?.plugin_icon?.startsWith('http'))
return `${import.meta.env.VITE_API_BASE_URL}system/img/${encodeURIComponent(props.plugin?.plugin_icon)}`
return `/plugin_icon/${props.plugin?.plugin_icon}`
})
// 访问插件页面
function visitPluginPage() {
// 将raw.githubusercontent.com转换为项目地址
let repoUrl = props.plugin?.repo_url
if (repoUrl) {
if (repoUrl.includes('raw.githubusercontent.com')) {
if (!repoUrl.endsWith('/'))
repoUrl += '/'
if (repoUrl.split('/').length < 6)
repoUrl = `${repoUrl}main/`
try {
const [user, repo] = repoUrl.split('/').slice(-4, -2)
repoUrl = `https://github.com/${user}/${repo}`
}
catch (error) {
return
}
}
}
else {
repoUrl = props.plugin?.author_url
}
window.open(repoUrl, '_blank')
}
// 弹出菜单
const dropdownItems = ref([
{
title: '查看详情',
value: 1,
props: {
prependIcon: 'mdi-information-outline',
click: visitPluginPage,
},
},
])
</script>
<template>
@@ -50,17 +138,51 @@ async function installPlugin() {
>
<div
class="relative pa-4 text-center card-cover-blurred"
:style="{ background: `${props.plugin?.plugin_color}` }"
: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"
: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>
<div
v-if="props.plugin?.has_update"
class="me-n3 absolute top-0 left-1"
>
<VIcon
icon="mdi-new-box"
class="text-white"
/>
</div>
<VAvatar
size="8rem"
:class="{ shadow: isImageLoaded }"
>
<VImg
:src="`/plugin_icon/${props.plugin?.plugin_icon}`"
ref="imageRef"
:src="iconPath"
aspect-ratio="4/3"
cover
@load="isImageLoaded = true"
:class="{ shadow: isImageLoaded }"
@load="imageLoaded"
@error="imageLoadError = true"
/>
</VAvatar>
</div>
@@ -76,9 +198,29 @@ async function installPlugin() {
@click.stop
>
{{ props.plugin?.plugin_author }}
</a>
</a><br>
版本{{ props.plugin?.plugin_version }}
</VCardText>
</VCard>
<!-- 安装插件进度框 -->
<VDialog
v-model="progressDialog"
:scrim="false"
width="25rem"
>
<VCard
color="primary"
>
<VCardText class="text-center">
{{ progressText }}
<VProgressLinear
indeterminate
color="white"
class="mb-0 mt-1"
/>
</VCardText>
</VCard>
</VDialog>
</template>
<style lang="scss" scoped>

View File

@@ -1,10 +1,13 @@
<script lang="ts" setup>
import { useToast } from 'vue-toast-notification'
import { useConfirm } from 'vuetify-use-dialog'
import api from '@/api'
import type { Plugin } from '@/api/types'
import FormRender from '@/components/render/FormRender.vue'
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'
// 输入参数
const props = defineProps({
@@ -16,9 +19,18 @@ const props = defineProps({
// 定义触发的自定义事件
const emit = defineEmits(['remove', 'save'])
// 背景颜色
const backgroundColor = ref('#28A9E1')
// 图片对象
const imageRef = ref<any>()
// 提示框
const $toast = useToast()
// 确认框
const createConfirm = useConfirm()
// 本身是否可见
const isVisible = ref(true)
@@ -31,17 +43,44 @@ const pluginConfigForm = ref({})
// 插件表单配置项
let pluginFormItems = reactive([])
// 插件详情页面
// 插件数据页面
const pluginInfoDialog = ref(false)
// 插件详情页面配置项
// 插件数据页面配置项
let pluginPageItems = reactive([])
// 图片是否加载完成
const isImageLoaded = ref(false)
// 图片是否加载失败
const imageLoadError = ref(false)
// 图片加载完成
async function imageLoaded() {
isImageLoaded.value = true
const imageElement = imageRef.value?.$el.querySelector('img') as HTMLImageElement
// 从图片中提取背景色
backgroundColor.value = await getDominantColor(imageElement)
}
// 调用API卸载插件
async function uninstallPlugin() {
const isConfirmed = await createConfirm({
title: '确认',
content: `是否确认卸载插件 ${props.plugin?.plugin_name} ?`,
confirmationText: '确认',
cancellationText: '取消',
dialogProps: {
maxWidth: '50rem',
},
confirmationButtonProps: {
variant: 'tonal',
},
})
if (!isConfirmed)
return
try {
const result: { [key: string]: any } = await api.delete(`plugin/${props.plugin?.id}`)
if (result.success) {
@@ -74,7 +113,7 @@ async function loadPluginForm() {
}
}
// 调用API读取详情页面
// 调用API读取数据页面
async function loadPluginPage() {
try {
const result: [] = await api.get(`plugin/page/${props.plugin?.id}`)
@@ -117,9 +156,9 @@ async function savePluginConf() {
}
}
// 显示插件详情
// 显示插件数据
async function showPluginInfo() {
// 加载详情
// 加载数据
await loadPluginPage()
pluginConfigDialog.value = false
pluginInfoDialog.value = true
@@ -136,10 +175,60 @@ async function showPluginConfig() {
pluginConfigDialog.value = true
}
// 计算图标路径
const iconPath: Ref<string> = computed(() => {
if (imageLoadError.value)
return noImage
// 如果是网络图片则使用代理后返回
if (props.plugin?.plugin_icon?.startsWith('http'))
return `${import.meta.env.VITE_API_BASE_URL}system/img/${encodeURIComponent(props.plugin?.plugin_icon)}`
return `/plugin_icon/${props.plugin?.plugin_icon}`
})
// 重置插件
async function resetPlugin() {
const isConfirmed = await createConfirm({
title: '确认',
content: `是否确认重置插件 ${props.plugin?.plugin_name} 的配置数据?`,
confirmationText: '确认',
cancellationText: '取消',
dialogProps: {
maxWidth: '50rem',
},
confirmationButtonProps: {
variant: 'tonal',
},
})
if (!isConfirmed)
return
try {
const result: { [key: string]: any } = await api.get(`plugin/reset/${props.plugin?.id}`)
if (result.success) {
$toast.success(`插件 ${props.plugin?.plugin_name} 数据已重置`)
// 通知父组件刷新
emit('save')
}
else {
$toast.error(`插件 ${props.plugin?.plugin_name} 重置失败:${result.message}}`)
}
}
catch (error) {
console.error(error)
}
}
// 访问作者主页
function visitAuthorPage() {
window.open(props.plugin?.author_url, '_blank')
}
// 弹出菜单
const dropdownItems = ref([
{
title: '查看详情',
title: '查看数据',
value: 1,
show: props.plugin?.has_page,
props: {
@@ -148,7 +237,7 @@ const dropdownItems = ref([
},
},
{
title: '置',
title: '置',
value: 2,
show: true,
props: {
@@ -157,15 +246,34 @@ const dropdownItems = ref([
},
},
{
title: '卸载',
title: '重置',
value: 3,
show: true,
props: {
prependIcon: 'mdi-cancel',
color: 'warning',
click: resetPlugin,
},
},
{
title: '卸载',
value: 4,
show: true,
props: {
prependIcon: 'mdi-trash-can-outline',
color: 'error',
click: uninstallPlugin,
},
},
{
title: '作者主页',
value: 4,
show: true,
props: {
prependIcon: 'mdi-home-circle-outline',
click: visitAuthorPage,
},
},
])
</script>
@@ -184,7 +292,7 @@ const dropdownItems = ref([
>
<div
class="relative pa-4 text-center card-cover-blurred"
:style="{ background: `${props.plugin?.plugin_color}` }"
:style="{ background: `${backgroundColor}` }"
>
<div class="me-n3 absolute top-0 right-3">
<IconBtn>
@@ -213,20 +321,22 @@ const dropdownItems = ref([
</div>
<VAvatar
size="8rem"
:class="{ shadow: isImageLoaded }"
>
<VImg
:src="`/plugin_icon/${props.plugin?.plugin_icon}`"
ref="imageRef"
:src="iconPath"
aspect-ratio="4/3"
cover
:class="{ shadow: isImageLoaded }"
@load="imageLoaded"
@error="imageLoadError = true"
/>
</VAvatar>
</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 }}
{{ props.plugin?.plugin_name }}<span class="text-sm ms-2 mt-1 text-gray-500">{{ props.plugin?.plugin_version }}</span>
</VCardTitle>
</VCardItem>
<VCardText>
@@ -254,7 +364,7 @@ const dropdownItems = ref([
</VCardText>
<VCardActions>
<VBtn v-if="pluginPageItems.length > 0" @click="showPluginInfo">
查看详情
查看数据
</VBtn>
<VSpacer />
<VBtn
@@ -267,7 +377,7 @@ const dropdownItems = ref([
</VCard>
</VDialog>
<!-- 插件详情页面 -->
<!-- 插件数据页面 -->
<VDialog
v-model="pluginInfoDialog"
scrollable

View File

@@ -33,9 +33,6 @@ const testButtonText = ref('测试')
// 测试按钮可用性
const testButtonDisable = ref(false)
// 更新按钮文字
const updateButtonText = ref('更新')
// 更新按钮可用性
const updateButtonDisable = ref(false)
@@ -48,6 +45,12 @@ const siteEditDialog = ref(false)
// 资源浏览弹窗
const resourceDialog = ref(false)
// 进度条
const progressDialog = ref(false)
// 进度文本
const progressText = ref('请稍候 ...')
// 资源浏览表头
const resourceHeaders = [
{ title: '标题', key: 'title', sortable: false },
@@ -138,9 +141,11 @@ async function updateSiteCookie() {
// 更新按钮状态
siteCookieDialog.value = false
updateButtonText.value = '更新中 ...'
updateButtonDisable.value = true
progressDialog.value = true
progressText.value = `正在更新 ${cardProps.site?.name} Cookie & UA ...`
const result: { [key: string]: any } = await api.get(
`site/cookie/${cardProps.site?.id}`,
{
@@ -156,7 +161,7 @@ async function updateSiteCookie() {
else
$toast.error(`${cardProps.site?.name} 更新失败:${result.message}`)
updateButtonText.value = '更新'
progressDialog.value = false
updateButtonDisable.value = false
}
catch (error) {
@@ -299,7 +304,7 @@ onMounted(() => {
<template #prepend>
<VIcon icon="mdi-refresh" />
</template>
{{ updateButtonText }}
更新
</VBtn>
<VBtn
:disabled="testButtonDisable"
@@ -488,6 +493,24 @@ onMounted(() => {
</VCardText>
</VCard>
</VDialog>
<VDialog
v-model="progressDialog"
:scrim="false"
width="25rem"
>
<VCard
color="primary"
>
<VCardText class="text-center">
{{ progressText }}
<VProgressLinear
indeterminate
color="white"
class="mb-0 mt-1"
/>
</VCardText>
</VCard>
</VDialog>
</template>
<style lang="scss">

View File

@@ -25,7 +25,6 @@ const tmdbKeyword = ref<HTMLElement | null>(null)
// 选中条目
function selectMedia(item: TmdbItem) {
console.log(item)
emit('update:modelValue', item.tmdbid)
emit('close')
}

View File

@@ -0,0 +1,39 @@
<script lang="ts" setup>
// 输入参数
const props = defineProps({
title: String,
})
// 定义事件
const emit = defineEmits(['update:modelValue', 'close'])
// 代码
const codeString = ref('')
// 导入
function handleImport() {
emit('update:modelValue', codeString.value)
emit('close')
}
</script>
<template>
<VCard
:title="props.title"
class="rounded-t"
>
<DialogCloseBtn @click="emit('close')" />
<VCardText class="pt-2">
<VTextarea v-model="codeString" />
</VCardText>
<VCardActions>
<VSpacer />
<VBtn
variant="tonal"
@click="handleImport"
>
导入
</VBtn>
</VCardActions>
</VCard>
</template>

View File

@@ -199,7 +199,7 @@ async function updateSiteInfo() {
md="4"
>
<VTextField
v-model="siteForm.limit_seconds"
v-model="siteForm.limit_count"
label="访问次数"
:rules="[numberValidator]"
/>

View File

@@ -39,6 +39,7 @@ const subscribeForm = ref<Subscribe>({
last_update: '',
username: '',
current_priority: 0,
save_path: '',
})
// 提示框
@@ -205,10 +206,11 @@ const effectOptions = ref([
},
])
// 初始化
onMounted(async () => {
getSiteList()
getSubscribeInfo()
watchEffect(() => {
if (props.subid) {
getSiteList()
getSubscribeInfo()
}
})
</script>
@@ -322,7 +324,21 @@ onMounted(async () => {
</VCol>
</VRow>
<VRow>
<VCol cols="12">
<VCol
cols="12"
md="4"
>
<VTextField
v-model="subscribeForm.save_path"
label="保存路径"
/>
</VCol>
</VRow>
<VRow>
<VCol
cols="12"
md="4"
>
<VSwitch
v-model="subscribeForm.best_version"
label="洗版"

View File

@@ -13,6 +13,9 @@ const route = useRoute()
// 标题
const title = route.query?.title?.toString()
// 类型
const type = route.query?.type?.toString()
// 计算API路径
function getApiPath(paths: string[] | string) {
if (Array.isArray(paths))
@@ -34,6 +37,7 @@ function getApiPath(paths: string[] | string) {
<PersonCardListView
:apipath="getApiPath(props.paths || '')"
:params="route.query"
:type="type"
/>
</div>
</template>

View File

@@ -33,7 +33,7 @@ const isImageLoaded = ref(false)
// 获取背景图片
async function fetchBackgroundImage() {
api
.get('/login/tmdb')
.get('/login/wallpaper')
.then((response: any) => {
backgroundImageUrl.value = response.message
})

View File

@@ -28,6 +28,18 @@ import MediaCardSlideView from '@/views/discover/MediaCardSlideView.vue'
title="热门电视剧"
/>
<MediaCardSlideView
apipath="douban/movie_hot"
linkurl="/browse/douban/movie_hot?title=热门电影"
title="热门电影"
/>
<MediaCardSlideView
apipath="douban/tv_hot"
linkurl="/browse/douban/tv_hot?title=热门电视剧"
title="热门电视剧"
/>
<MediaCardSlideView
apipath="douban/tv_animation"
linkurl="/browse/douban/tv_animation?title=热门动漫"

View File

@@ -6,6 +6,10 @@ import { hexToRgb } from '@layouts/utils'
const vuetifyTheme = useTheme()
// 从Vuex Store中获取信息
const store = useStore()
const superUser = store.state.auth.superUser
const options = controlledComputed(
() => vuetifyTheme.name.value,
() => {
@@ -129,6 +133,7 @@ onMounted(() => {
</div>
<VBtn
v-if="superUser"
block
to="/history"
>

View File

@@ -156,7 +156,7 @@ async function fetchData({ done }: { done: any }) {
v-if="dataList.length === 0 && isRefreshed"
error-code="404"
error-title="没有数据"
error-description="无法获取到TMDB媒体信息"
error-description="无法获取到媒体信息"
/>
</VInfiniteScroll>
</template>

View File

@@ -37,14 +37,14 @@ const isRefreshed = ref(false)
// 存储每一季的集信息
const seasonEpisodesInfo = ref({} as { [key: number]: TmdbEpisode[] })
// 各季缺失状态0-已存在 1-部分缺失 2-全部缺失,没有数据也是已存在
// 各季缺失状态0-已入库 1-部分缺失 2-全部缺失,没有数据也是已入库
const seasonsNotExisted = ref<{ [key: number]: number }>({})
// 各季的订阅状态
const seasonsSubscribed = ref<{ [key: number]: boolean }>({})
// 订阅编号
const subscribeId = ref(0)
const subscribeId = ref<number>()
// 调用API查询详情
async function getMediaDetail() {
@@ -85,7 +85,7 @@ async function loadSeasonEpisodes(season: number) {
}
}
// 查询当前媒体是否已存在
// 查询当前媒体是否已入库
async function checkMovieExists() {
try {
const result: { [key: string]: any } = await api.get('media/exists', {
@@ -109,11 +109,12 @@ async function checkMovieExists() {
// 查询当前媒体是否已订阅
async function checkSubscribe(season = 0) {
try {
const mediaid = `tmdb:${mediaDetail.value.tmdb_id}`
const mediaid = mediaDetail.value.tmdb_id ? `tmdb:${mediaDetail.value.tmdb_id}` : `douban:${mediaDetail.value.douban_id}`
const result: Subscribe = await api.get(`subscribe/media/${mediaid}`, {
params: {
season,
title: mediaDetail.value.title,
},
})
@@ -138,7 +139,7 @@ async function checkSeasonsNotExists() {
isExists.value = true
result.forEach((item) => {
// 0-已存在 1-部分缺失 2-全部缺失
// 0-已入库 1-部分缺失 2-全部缺失
let state = 0
if (item.episodes.length === 0)
state = 2
@@ -358,14 +359,14 @@ function getExistColor(season: number) {
function getExistText(season: number) {
const state = seasonsNotExisted.value[season]
if (!state)
return '已存在'
return '已入库'
if (state === 1)
return '部分缺失'
else if (state === 2)
return '缺失'
else
return '已存在'
return '已入库'
}
// 计算订阅图标
@@ -391,10 +392,11 @@ function joinArray(arr: string[]) {
// 开始搜索
function handleSearch(area: string) {
const keyword = mediaDetail.value.tmdb_id ? `tmdb:${mediaDetail.value.tmdb_id}` : `douban:${mediaDetail.value.douban_id}`
router.push({
path: '/resource',
query: {
keyword: `tmdb:${mediaDetail.value.tmdb_id}`,
keyword,
type: mediaDetail.value.type,
area,
},
@@ -418,9 +420,9 @@ onBeforeMount(() => {
/>
</div>
<div v-if="mediaDetail.tmdb_id || mediaDetail.douban_id" class="max-w-8xl mx-auto px-4">
<template v-if="mediaDetail.backdrop_path">
<template v-if="mediaDetail.backdrop_path || mediaDetail.poster_path">
<div class="vue-media-back absolute left-0 top-0 w-full h-96">
<VImg class="h-96" :src="mediaDetail.backdrop_path" cover />
<VImg class="h-96" :src="mediaDetail.backdrop_path || mediaDetail.poster_path" cover />
</div>
<div class="vue-media-back absolute left-0 top-0 w-full h-96" />
</template>
@@ -456,7 +458,7 @@ onBeforeMount(() => {
</span>
</div>
<div class="media-actions">
<VBtn v-if="mediaDetail.tmdb_id" variant="tonal" color="info">
<VBtn v-if="mediaDetail.tmdb_id || mediaDetail.douban_id" variant="tonal" color="info">
<template #prepend>
<VIcon icon="mdi-magnify" />
</template>
@@ -482,7 +484,7 @@ onBeforeMount(() => {
</VList>
</VMenu>
</VBtn>
<VBtn v-if="mediaDetail.type === '电影'" class="ms-2" :color="getSubscribeColor" variant="tonal" @click="handleSubscribe(0)">
<VBtn v-if="mediaDetail.type === '电影' || mediaDetail.douban_id" class="ms-2" :color="getSubscribeColor" variant="tonal" @click="handleSubscribe(0)">
<template #prepend>
<VIcon :icon="getSubscribeIcon" />
</template>
@@ -510,10 +512,6 @@ onBeforeMount(() => {
<span>{{ joinArray(director.roles) }}</span>
<a class="crew-name" :href="`${director.url}`" target="_blank">{{ director.name }}</a>
</li>
<li v-for="director in mediaDetail.actors" :key="director.id">
<span>{{ joinArray(director.roles) }}</span>
<a class="crew-name" :href="`${director.url}`" target="_blank">{{ director.name }}</a>
</li>
</ul>
<div class="mt-6">
<a v-if="mediaDetail.tmdb_id" class="mb-2 mr-2 inline-flex last:mr-0" :href="getTheMovieDbLink()" target="_blank">
@@ -665,12 +663,56 @@ onBeforeMount(() => {
</div>
</div>
</div>
<div v-else-if="mediaDetail.douban_id" class="media-overview-right">
<div class="media-facts">
<div v-if="mediaDetail.vote_average" class="media-ratings">
<VRating
v-model="mediaDetail.vote_average"
density="compact"
length="10"
class="ma-2"
readonly
/>
</div>
<div v-if="mediaDetail.douban_id" class="media-fact">
<span>豆瓣ID</span>
<span class="media-fact-value">{{ mediaDetail.douban_id }}</span>
</div>
<div v-if="mediaDetail.original_title" class="media-fact">
<span>原始标题</span>
<span class="media-fact-value">{{ mediaDetail.original_title }}</span>
</div>
<div v-if="mediaDetail.release_date" class="media-fact">
<span>上映日期</span>
<span class="media-fact-value">
{{ mediaDetail.release_date }}
</span>
</div>
<div v-if="mediaDetail.production_countries" class="media-fact border-b-0">
<span>出品国家</span>
<span class="media-fact-value">
<span v-for="country in getProductionCountries" :key="country" class="flex items-center justify-end text-end">
{{ country }}
</span>
</span>
</div>
</div>
</div>
</div>
<div v-if="mediaDetail.tmdb_id">
<PersonCardSlideView
:apipath="`tmdb/credits/${mediaDetail.tmdb_id}/${mediaProps.type}`"
:linkurl="`/credits/tmdb/credits/${mediaDetail.tmdb_id}/${mediaProps.type}?title=演员阵容`"
:linkurl="`/credits/tmdb/credits/${mediaDetail.tmdb_id}/${mediaProps.type}?title=演员阵容&type=tmdb`"
title="演员阵容"
type="tmdb"
/>
</div>
<div v-else-if="mediaDetail.douban_id">
<PersonCardSlideView
:apipath="`douban/credits/${mediaDetail.douban_id}/${mediaProps.type}`"
:linkurl="`/credits/douban/credits/${mediaDetail.douban_id}/${mediaProps.type}?title=演员阵容&type=douban`"
title="演员阵容"
type="douban"
/>
</div>
<div v-if="mediaDetail.tmdb_id">
@@ -680,6 +722,13 @@ onBeforeMount(() => {
title="推荐"
/>
</div>
<div v-else-if="mediaDetail.douban_id">
<MediaCardSlideView
:apipath="`douban/recommend/${mediaDetail.douban_id}/${mediaProps.type}`"
:linkurl="`/browse/douban/recommend/${mediaDetail.douban_id}/${mediaProps.type}?title=推荐`"
title="推荐"
/>
</div>
<div v-if="mediaDetail.tmdb_id">
<MediaCardSlideView
:apipath="`tmdb/similar/${mediaDetail.tmdb_id}/${mediaProps.type}`"
@@ -693,7 +742,7 @@ onBeforeMount(() => {
v-if="!mediaDetail.tmdb_id && !mediaDetail.douban_id && isRefreshed"
error-code="500"
error-title="出错啦"
error-description="未识别到TMDB媒体信息"
error-description="未识别到媒体信息"
/>
<!-- 订阅编辑弹窗 -->
<SubscribeEditForm

View File

@@ -1,13 +1,14 @@
<script lang="ts" setup>
import api from '@/api'
import type { TmdbPerson } from '@/api/types'
import PersonCard from '@/components/cards/PersonCard.vue'
import DoubanPersonCard from '@/components/cards/DoubanPersonCard.vue'
import TmdbPersonCard from '@/components/cards/TmdbPersonCard.vue'
import NoDataFound from '@/components/NoDataFound.vue'
// 输入参数
const props = defineProps({
apipath: String,
params: Object as PropType<{ [key: string]: any }>,
type: String,
})
// 判断是否有滚动条
@@ -29,8 +30,8 @@ const loading = ref(false)
const isRefreshed = ref(false)
// 数据列表
const dataList = ref<TmdbPerson[]>([])
const currData = ref<TmdbPerson[]>([])
const dataList = ref<any>([])
const currData = ref<any>([])
// 获取列表数据
async function fetchData({ done }: { done: any }) {
@@ -135,11 +136,22 @@ async function fetchData({ done }: { done: any }) {
>
<template #loading />
<div
v-if="dataList.length > 0"
v-if="dataList.length > 0 && props.type === 'tmdb'"
class="grid gap-4 grid-media-card mx-3"
tabindex="0"
>
<PersonCard
<TmdbPersonCard
v-for="data in dataList"
:key="data.id"
:person="data"
/>
</div>
<div
v-if="dataList.length > 0 && props.type === 'douban'"
class="grid gap-4 grid-media-card mx-3"
tabindex="0"
>
<DoubanPersonCard
v-for="data in dataList"
:key="data.id"
:person="data"
@@ -149,7 +161,7 @@ async function fetchData({ done }: { done: any }) {
v-if="dataList.length === 0 && isRefreshed"
error-code="404"
error-title="没有数据"
error-description="无法获取到TMDB媒体信息"
error-description="无法获取到媒体信息"
/>
</VInfiniteScroll>
</template>

View File

@@ -1,21 +1,22 @@
<script lang="ts" setup>
import PersionCard from '@/components/cards/PersonCard.vue'
import TmdbPersonCard from '@/components/cards/TmdbPersonCard.vue'
import api from '@/api'
import type { TmdbPerson } from '@/api/types'
import SlideView from '@/components/slide/SlideView.vue'
import DoubanPersonCard from '@/components/cards/DoubanPersonCard.vue'
// 输入参数
const props = defineProps({
apipath: String,
linkurl: String,
title: String,
type: String,
})
// 组件加载完成
const componentLoaded = ref(false)
// 数据列表
const dataList = ref<TmdbPerson[]>([])
const dataList = ref<any>([])
// 获取订阅列表数据
async function fetchData() {
@@ -46,7 +47,14 @@ onMounted(fetchData)
v-for="data in dataList"
:key="data.id"
>
<PersionCard
<TmdbPersonCard
v-if="props.type === 'tmdb'"
:person="data"
height="15rem"
width="10rem"
/>
<DoubanPersonCard
v-if="props.type === 'douban'"
:person="data"
height="15rem"
width="10rem"

View File

@@ -80,7 +80,7 @@ watchEffect(() => {
// group data
const key = `${torrent_info.title}_${torrent_info.size}`
if (groupMap.has(key)) {
// 已存在相同标题和大小的分组,将当前上下文信息添加到分组中
// 已入库相同标题和大小的分组,将当前上下文信息添加到分组中
const group = groupMap.get(key)
group?.push(item)
}

View File

@@ -19,9 +19,9 @@ const getInstalledPluginList = computed(() => {
return dataList.value.filter(item => item.installed)
})
// 获取未安装的插件列表
// 获取未安装或者有更新的插件列表
const getUninstalledPluginList = computed(() => {
return dataList.value.filter(item => !item.installed)
return dataList.value.filter(item => !item.installed || item.has_update)
})
// 关闭插件市场窗口
@@ -84,13 +84,14 @@ onBeforeMount(fetchData)
<VDialog
v-model="PluginAppDialog"
fullscreen
scrollable
:scrim="false"
transition="dialog-bottom-transition"
>
<!-- Dialog Activator -->
<template #activator="{ props }">
<VBtn
icon="mdi-plus"
icon="mdi-store-plus"
v-bind="props"
size="x-large"
class="fixed right-5 bottom-5"
@@ -119,7 +120,7 @@ onBeforeMount(fetchData)
</VToolbarItems>
</VToolbar>
</div>
<div class="pa-4">
<VCardText>
<div class="grid gap-4 grid-plugin-card">
<PluginAppCard
v-for="data in getUninstalledPluginList"
@@ -134,7 +135,7 @@ onBeforeMount(fetchData)
error-title="没有未安装插件"
error-description="所有可用插件均已安装"
/>
</div>
</VCardText>
</VCard>
</VDialog>
</template>

View File

@@ -40,6 +40,9 @@ const dataList = ref<TransferHistory[]>([])
// 搜索
const search = ref('')
// 搜索提示词列表
const searchHintList = ref<string[]>([])
// 加载状态
const loading = ref(false)
@@ -47,7 +50,7 @@ const loading = ref(false)
const totalItems = ref(0)
// 每页条数
const itemsPerPage = ref(25)
const itemsPerPage = ref(50)
// 当前页码
const currentPage = ref(1)
@@ -89,6 +92,7 @@ async function fetchData({
dataList.value = result.data.list
totalItems.value = result.data.total
searchHintList.value = [...new Set(dataList.value.map(item => item.title || ''))].filter(title => title !== '')
}
catch (error) {
console.error(error)
@@ -210,6 +214,21 @@ async function removeHistoryBatch() {
deleteConfirmDialog.value = true
}
// 计算根路径
function getRootPath(path: string, type: string, category: string) {
if (!path)
return ''
let index = -2
if (type !== '电影')
index = -3
if (category)
index -= 1
if (path.includes('/'))
return path.split('/').slice(0, index).join('/')
else
return path.split('\\').slice(0, index).join('\\')
}
// 批量重新整理
async function retransferBatch() {
if (selected.value.length === 0)
@@ -219,10 +238,19 @@ async function retransferBatch() {
// 重新整理IDS
redoIds.value = selected.value.map(item => item.id)
// 重新整理target
if (selected.value.length === 1)
redoTarget.value = selected.value[0].dest ?? ''
else
if (selected.value.length === 1) {
// 目的目录
const dest = selected.value[0].dest ?? ''
// 类型
const mediaType = selected.value[0].type ?? ''
// 分类
const category = selected.value[0].category ?? ''
// 计算根路径
redoTarget.value = getRootPath(dest, mediaType, category)
}
else {
redoTarget.value = ''
}
// 打开识别弹窗
redoDialog.value = true
}
@@ -236,7 +264,7 @@ const dropdownItems = ref([
prependIcon: 'mdi-redo-variant',
click: (item: TransferHistory) => {
redoIds.value = [item.id]
redoTarget.value = item.dest ?? ''
redoTarget.value = getRootPath(item.dest ?? '', item.type ?? '', item.category ?? '')
redoDialog.value = true
},
},
@@ -262,9 +290,10 @@ const dropdownItems = ref([
<VRow>
<VCol> 历史记录 </VCol>
<VCol>
<VTextField
<VCombobox
key="search_navbar"
v-model="search"
:items="searchHintList"
class="text-disabled"
density="compact"
label="搜索"
@@ -274,6 +303,7 @@ const dropdownItems = ref([
hide-details
flat
rounded
clearable
/>
</VCol>
</VRow>

View File

@@ -84,7 +84,7 @@ onMounted(() => {
<div>
<div class="max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4">
<dt class="block text-sm font-bold">
当前版本
软件版本
</dt>
<dd class="flex text-sm sm:col-span-2 sm:mt-0">
<span class="flex-grow flex flex-row items-center truncate">
@@ -98,6 +98,30 @@ onMounted(() => {
</dd>
</div>
</div>
<div>
<div class="max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4">
<dt class="block text-sm font-bold">
认证资源版本
</dt>
<dd class="flex text-sm sm:col-span-2 sm:mt-0">
<span class="flex-grow flex flex-row items-center truncate">
<code class="truncate">{{ systemEnv.AUTH_VERSION }}</code>
</span>
</dd>
</div>
</div>
<div>
<div class="max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4">
<dt class="block text-sm font-bold">
站点资源版本
</dt>
<dd class="flex text-sm sm:col-span-2 sm:mt-0">
<span class="flex-grow flex flex-row items-center truncate">
<code class="truncate">{{ systemEnv.INDEXER_VERSION }}</code>
</span>
</dd>
</div>
</div>
<div>
<div class="max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4">
<dt class="block text-sm font-bold">

View File

@@ -147,6 +147,10 @@ async function deactivateUser(user: User) {
// 新增用户
async function addUser() {
if (!userForm.name || !userForm.password || !userForm.email) {
$toast.error('请填写完整信息!')
return
}
try {
const result: { [key: string]: any } = await api.post('user', userForm)
if (result.success) {
@@ -447,6 +451,7 @@ onMounted(() => {
>
<VTextField
v-model="userForm.email"
:rules="[requiredValidator]"
label="邮箱"
/>
</VCol>

View File

@@ -3,6 +3,8 @@ import { useToast } from 'vue-toast-notification'
import api from '@/api'
import FilterRuleCard from '@/components/cards/FilterRuleCard.vue'
import type { Site } from '@/api/types'
import { copyToClipboard } from '@/@core/utils/navigator'
import ImportCodeForm from '@/components/form/ImportCodeForm.vue'
// 规则卡片类型
interface FilterCard {
@@ -30,6 +32,12 @@ const defaultFilterRules = ref({
exclude: '',
})
// 导入代码弹窗
const importCodeDialog = ref(false)
// 导入的代码
const importCodeString = ref('')
// 查询已设置优先级规则
async function queryCustomFilters() {
try {
@@ -227,6 +235,49 @@ async function saveDefaultFilter() {
}
}
// 分享规则
function shareRules() {
// 有值才处理
if (filterCards.value.length === 0)
return
// 将卡片规则接装为字符串
const value = filterCards.value
.filter(card => card.rules.length > 0)
.map(card => card.rules.join('&'))
.join('>')
// 复制到剪贴板
try {
copyToClipboard(value)
$toast.success('优先级规则已复制到剪贴板')
}
catch (error) {
$toast.error('优先级规则复制失败!')
}
}
// 监听导入代码变化
watchEffect(() => {
if (!importCodeString.value)
return
// 导入代码需要以空格开头和结束,没有则拼接
if (!importCodeString.value.startsWith(' '))
importCodeString.value = ` ${importCodeString.value}`
if (!importCodeString.value.endsWith(' '))
importCodeString.value = `${importCodeString.value} `
// 将导入的代码转换为规则卡片
const groups = importCodeString.value.split('>')
filterCards.value = groups.map((group: string, index: number) => {
return {
pri: (index + 1).toString(),
rules: group.split('&'),
}
})
})
onMounted(() => {
queryCustomFilters()
querySites()
@@ -264,6 +315,36 @@ onMounted(() => {
</VCol>
<VCol cols="12">
<VCard title="搜索优先级">
<template #append>
<IconBtn>
<VIcon icon="mdi-dots-vertical" />
<VMenu
activator="parent"
close-on-content-click
>
<VList>
<VListItem
variant="plain"
@click="shareRules"
>
<template #prepend>
<VIcon icon="mdi-share" />
</template>
<VListItemTitle>分享</VListItemTitle>
</VListItem>
<VListItem
variant="plain"
@click="importCodeDialog = true"
>
<template #prepend>
<VIcon icon="mdi-import" />
</template>
<VListItemTitle>导入</VListItemTitle>
</VListItem>
</VList>
</VMenu>
</IconBtn>
</template>
<VCardSubtitle> 设置在搜索时默认使用的优先级排序未在优先级中的资源将不在搜索结果中显示 </VCardSubtitle>
<VCardItem>
<div class="grid gap-3 grid-filterrule-card">
@@ -332,6 +413,17 @@ onMounted(() => {
</VCard>
</VCol>
</VRow>
<VDialog
v-model="importCodeDialog"
width="60rem"
scrollable
>
<ImportCodeForm
v-model="importCodeString"
title="导入优先级规则"
@close="importCodeDialog = false"
/>
</VDialog>
</template>
<style lang="scss">

View File

@@ -3,6 +3,8 @@ import { useToast } from 'vue-toast-notification'
import api from '@/api'
import FilterRuleCard from '@/components/cards/FilterRuleCard.vue'
import type { Site } from '@/api/types'
import { copyToClipboard } from '@/@core/utils/navigator'
import ImportCodeForm from '@/components/form/ImportCodeForm.vue'
// 规则卡片类型
interface FilterCard {
@@ -27,12 +29,21 @@ const allSites = ref<Site[]>([])
// 选中订阅站点
const selectedRssSites = ref<number[]>([])
// 当前规则类型
const currentRuleType = ref('SubscribeFilterRules')
// 包含与排除规则
const defaultFilterRules = ref({
include: '',
exclude: '',
})
// 导入代码弹窗
const importCodeDialog = ref(false)
// 导入的代码
const importCodeString = ref('')
// 查询用户选中的订阅站点
async function querySelectedRssSites() {
try {
@@ -244,6 +255,66 @@ async function saveDefaultFilter() {
}
}
// 分享规则
function shareRules(ruleType: string) {
let filterCards: Ref<FilterCard[]>
if (ruleType === 'SubscribeFilterRules')
filterCards = subscribeFilterCards
else
filterCards = bestVersionFilterCards
// 有值才处理
if (filterCards.value.length === 0)
return
// 将卡片规则接装为字符串
const value = filterCards.value
.filter(card => card.rules.length > 0)
.map(card => card.rules.join('&'))
.join('>')
// 复制到剪贴板
try {
copyToClipboard(value)
$toast.success('优先级规则已复制到剪贴板')
}
catch (error) {
$toast.error('优先级规则复制失败!')
}
}
// 导入规则
async function importRules(ruleType: string) {
currentRuleType.value = ruleType
importCodeString.value = ''
importCodeDialog.value = true
}
// 监听导入代码变化
watchEffect(() => {
if (!importCodeString.value)
return
if (!currentRuleType.value)
return
// 导入代码需要以空格开头和结束,没有则拼接
if (!importCodeString.value.startsWith(' '))
importCodeString.value = ` ${importCodeString.value}`
if (!importCodeString.value.endsWith(' '))
importCodeString.value = `${importCodeString.value} `
let filterCards: Ref<FilterCard[]>
if (currentRuleType.value === 'SubscribeFilterRules')
filterCards = subscribeFilterCards
else
filterCards = bestVersionFilterCards
// 将导入的代码转换为规则卡片
const groups = importCodeString.value.split('>')
filterCards.value = groups.map((group: string, index: number) => {
return {
pri: (index + 1).toString(),
rules: group.split('&'),
}
})
})
onMounted(() => {
querySites()
queryCustomFilters('SubscribeFilterRules')
@@ -282,6 +353,36 @@ onMounted(() => {
</VCol>
<VCol cols="12">
<VCard title="订阅优先级">
<template #append>
<IconBtn>
<VIcon icon="mdi-dots-vertical" />
<VMenu
activator="parent"
close-on-content-click
>
<VList>
<VListItem
variant="plain"
@click="shareRules('SubscribeFilterRules')"
>
<template #prepend>
<VIcon icon="mdi-share" />
</template>
<VListItemTitle>分享</VListItemTitle>
</VListItem>
<VListItem
variant="plain"
@click="importRules('SubscribeFilterRules')"
>
<template #prepend>
<VIcon icon="mdi-import" />
</template>
<VListItemTitle>导入</VListItemTitle>
</VListItem>
</VList>
</VMenu>
</IconBtn>
</template>
<VCardSubtitle> 设置在正常订阅时默认使用的优先级未在优先级中的资源将不会自动下载 </VCardSubtitle>
<VCardItem>
<div class="grid gap-3 grid-filterrule-card">
@@ -318,6 +419,36 @@ onMounted(() => {
</VCol>
<VCol cols="12">
<VCard title="洗版优先级">
<template #append>
<IconBtn>
<VIcon icon="mdi-dots-vertical" />
<VMenu
activator="parent"
close-on-content-click
>
<VList>
<VListItem
variant="plain"
@click="shareRules('BestVersionFilterRules')"
>
<template #prepend>
<VIcon icon="mdi-share" />
</template>
<VListItemTitle>分享</VListItemTitle>
</VListItem>
<VListItem
variant="plain"
@click="importRules('BestVersionFilterRules')"
>
<template #prepend>
<VIcon icon="mdi-import" />
</template>
<VListItemTitle>导入</VListItemTitle>
</VListItem>
</VList>
</VMenu>
</IconBtn>
</template>
<VCardSubtitle> 设置在订阅洗版时使用的优先级匹配优先级1时洗版完成 </VCardSubtitle>
<VCardItem>
<div class="grid gap-3 grid-filterrule-card">
@@ -386,6 +517,17 @@ onMounted(() => {
</VCard>
</VCol>
</VRow>
<VDialog
v-model="importCodeDialog"
width="60rem"
scrollable
>
<ImportCodeForm
v-model="importCodeString"
title="导入优先级规则"
@close="importCodeDialog = false"
/>
</VDialog>
</template>
<style lang="scss">

View File

@@ -166,13 +166,26 @@ onMounted(() => {
<VTextarea
v-model="customIdentifiers"
auto-grow
placeholder="支持正则表达式,特殊字符需要\转义,一行为一组,支持以下几种配置格式:
屏蔽词
被替换词 => 替换词
前定位词 <> 后定位词 >> 集偏移量EP
被替换词 => 替换词 && 前定位词 <> 后定位词 >> 集偏移量EP"
placeholder="支持正则表达式,特殊字符需要\转义,一行为一组"
/>
</VCardItem>
<VCardItem>
<VAlert
type="info"
variant="tonal"
title="支持的配置格式(注意空格):"
>
<span
v-html="`
屏蔽词<br>
被替换词 => 替换词<br>
前定位词 <> 后定位词 >> 集偏移量EP<br>
被替换词 => 替换词 && 前定位词 <> 后定位词 >> 集偏移量EP<br>
其中替换词支持格式:{[tmdbid/doubanid=xxx;type=movie/tv;s=xxx;e=xxx]} 直接指定TMDBID/豆瓣ID识别其中s、e为季数和集数可选<br>
`"
/>
</VAlert>
</VCardItem>
<VCardItem>
<VBtn
type="submit"

359
yarn.lock
View File

@@ -1703,6 +1703,11 @@
resolved "https://registry.yarnpkg.com/@kurkle/color/-/color-0.3.2.tgz#5acd38242e8bde4f9986e7913c8fdf49d3aa199f"
integrity sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==
"@lokesh.dhakar/quantize@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@lokesh.dhakar/quantize/-/quantize-1.3.0.tgz#04476889953aca94614fbc79e9a43adc7979179a"
integrity sha512-4KBSyaMj65d8A+2vnzLxtHFu4OmBU4IKO0yLxZ171Itdf9jGV4w+WbG7VsKts2jUdRkFSzsZqpZOz6hTB3qGAw==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -2432,7 +2437,7 @@ acorn@^8.5.0, acorn@^8.8.0, acorn@^8.8.2:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
ajv@^6.10.0, ajv@^6.12.4:
ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -2560,6 +2565,18 @@ arrify@^1.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==
asn1@~0.2.3:
version "0.2.6"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d"
integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==
dependencies:
safer-buffer "~2.1.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==
ast-walker-scope@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/ast-walker-scope/-/ast-walker-scope-0.4.1.tgz#81ae35fc86f357689dae5a4721d743831e3c240e"
@@ -2605,6 +2622,16 @@ available-typed-arrays@^1.0.5:
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==
aws4@^1.8.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3"
integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==
axios-mock-adapter@^1.21.4:
version "1.21.4"
resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.21.4.tgz#ced09b54b245b338422e3af425ae529bfa26e051"
@@ -2656,6 +2683,13 @@ balanced-match@^2.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9"
integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==
dependencies:
tweetnacl "^0.14.3"
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
@@ -2805,6 +2839,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464, can
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz"
integrity sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -2930,7 +2969,15 @@ colord@^2.9.1, colord@^2.9.3:
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
combined-stream@^1.0.8:
colorthief@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/colorthief/-/colorthief-2.4.0.tgz#74e6edd142695655bd5f52c7f8116b125ea2b2bd"
integrity sha512-0U48RGNRo5fVO+yusBwgp+d3augWSorXabnqXUu9SabEhCpCgZJEUjUTTI41OOBBYuMMxawa3177POT6qLfLeQ==
dependencies:
"@lokesh.dhakar/quantize" "^1.3.0"
get-pixels "^3.3.2"
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@@ -3011,6 +3058,11 @@ core-js-compat@^3.30.1, core-js-compat@^3.30.2:
dependencies:
browserslist "^4.21.5"
core-util-is@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==
cosmiconfig@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
@@ -3170,6 +3222,25 @@ csstype@^3.1.1:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
cwise-compiler@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/cwise-compiler/-/cwise-compiler-1.1.3.tgz#f4d667410e850d3a313a7d2db7b1e505bb034cc5"
integrity sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==
dependencies:
uniq "^1.0.0"
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==
dependencies:
assert-plus "^1.0.0"
data-uri-to-buffer@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-0.0.3.tgz#18ae979a6a0ca994b0625853916d2662bbae0b1a"
integrity sha512-Cp+jOa8QJef5nXS5hU7M1DWzXPEIoVR3kbV0dQuVGwROZg8bGf1DcCnkmajBTnvghTtSNMUdRrPjgaT6ZQucbw==
de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
@@ -3357,6 +3428,14 @@ domutils@^3.0.1:
domelementtype "^2.3.0"
domhandler "^5.0.3"
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==
dependencies:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -4051,6 +4130,11 @@ express@^4.18.2:
utils-merge "1.0.1"
vary "~1.1.2"
extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extract-comments@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/extract-comments/-/extract-comments-1.1.0.tgz#b90bca033a056bd69b8ba1c6b6b120fc2ee95c18"
@@ -4070,6 +4154,16 @@ extract-zip@^2.0.1:
optionalDependencies:
"@types/yauzl" "^2.9.1"
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==
extsprintf@^1.2.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -4204,6 +4298,11 @@ for-each@^0.3.3:
dependencies:
is-callable "^1.1.3"
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==
form-data@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
@@ -4222,6 +4321,15 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.6"
mime-types "^2.1.12"
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -4303,6 +4411,23 @@ get-own-enumerable-property-symbols@^3.0.0:
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
get-pixels@^3.3.2:
version "3.3.3"
resolved "https://registry.yarnpkg.com/get-pixels/-/get-pixels-3.3.3.tgz#71e2dfd4befb810b5478a61c6354800976ce01c7"
integrity sha512-5kyGBn90i9tSMUVHTqkgCHsoWoR+/lGbl4yC83Gefyr0HLIhgSWEx/2F/3YgsZ7UpYNuM6pDhDK7zebrUJ5nXg==
dependencies:
data-uri-to-buffer "0.0.3"
jpeg-js "^0.4.1"
mime-types "^2.0.1"
ndarray "^1.0.13"
ndarray-pack "^1.1.1"
node-bitmap "0.0.1"
omggif "^1.0.5"
parse-data-uri "^0.2.0"
pngjs "^3.3.3"
request "^2.44.0"
through "^2.3.4"
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
@@ -4328,6 +4453,13 @@ get-tsconfig@^4.5.0:
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.5.0.tgz#6d52d1c7b299bd3ee9cd7638561653399ac77b0f"
integrity sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==
dependencies:
assert-plus "^1.0.0"
glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@@ -4467,6 +4599,19 @@ grapheme-splitter@^1.0.4:
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==
har-validator@~5.1.3:
version "5.1.5"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
dependencies:
ajv "^6.12.3"
har-schema "^2.0.0"
hard-rejection@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
@@ -4561,6 +4706,15 @@ http-errors@2.0.0:
statuses "2.0.1"
toidentifier "1.0.1"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
@@ -4638,6 +4792,11 @@ internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5:
has "^1.0.3"
side-channel "^1.0.4"
iota-array@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/iota-array/-/iota-array-1.0.0.tgz#81ef57fe5d05814cd58c2483632a99c30a0e8087"
integrity sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
@@ -4700,6 +4859,11 @@ is-boolean-object@^1.1.0:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
is-buffer@^1.0.2:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-buffer@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
@@ -4865,6 +5029,11 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.9:
gopd "^1.0.1"
has-tostringtag "^1.0.0"
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
is-weakmap@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2"
@@ -4902,6 +5071,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
jake@^10.8.5:
version "10.8.7"
resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f"
@@ -4926,6 +5100,11 @@ jiti@^1.18.2:
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd"
integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==
jpeg-js@^0.4.1:
version "0.4.4"
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa"
integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==
js-sdsl@^4.1.4:
version "4.4.0"
resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430"
@@ -4948,6 +5127,11 @@ js-yaml@^4.1.0:
dependencies:
argparse "^2.0.1"
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
@@ -4978,7 +5162,7 @@ json-schema-traverse@^1.0.0:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
json-schema@^0.4.0:
json-schema@0.4.0, json-schema@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
@@ -4988,6 +5172,11 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
json5@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
@@ -5040,6 +5229,16 @@ jsonpointer@^5.0.0:
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559"
integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==
jsprim@^1.2.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb"
integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.4.0"
verror "1.10.0"
jwt-decode@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
@@ -5297,7 +5496,7 @@ mime-db@1.52.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34:
mime-types@^2.0.1, mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
@@ -5445,11 +5644,32 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
ndarray-pack@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ndarray-pack/-/ndarray-pack-1.2.1.tgz#8caebeaaa24d5ecf70ff86020637977da8ee585a"
integrity sha512-51cECUJMT0rUZNQa09EoKsnFeDL4x2dHRT0VR5U2H5ZgEcm95ZDWcMA5JShroXjHOejmAD/fg8+H+OvUnVXz2g==
dependencies:
cwise-compiler "^1.1.2"
ndarray "^1.0.13"
ndarray@^1.0.13:
version "1.0.19"
resolved "https://registry.yarnpkg.com/ndarray/-/ndarray-1.0.19.tgz#6785b5f5dfa58b83e31ae5b2a058cfd1ab3f694e"
integrity sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==
dependencies:
iota-array "^1.0.0"
is-buffer "^1.0.2"
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
node-bitmap@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/node-bitmap/-/node-bitmap-0.0.1.tgz#180eac7003e0c707618ef31368f62f84b2a69091"
integrity sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==
node-fetch@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6"
@@ -5521,6 +5741,11 @@ nth-check@^2.0.1:
dependencies:
boolbase "^1.0.0"
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
object-assign@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -5577,6 +5802,11 @@ object.values@^1.1.6:
define-properties "^1.1.4"
es-abstract "^1.20.4"
omggif@^1.0.5:
version "1.0.10"
resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19"
integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
@@ -5676,6 +5906,13 @@ parse-code-context@^1.0.0:
resolved "https://registry.yarnpkg.com/parse-code-context/-/parse-code-context-1.0.0.tgz#718c295c593d0d19a37f898473268cc75e98de1e"
integrity sha512-OZQaqKaQnR21iqhlnPfVisFjBWjhnMl5J9MgbP8xC+EwoVqbXrq78lp+9Zb3ahmLzrIX5Us/qbvBnaS3hkH6OA==
parse-data-uri@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/parse-data-uri/-/parse-data-uri-0.2.0.tgz#bf04d851dd5c87b0ab238e5d01ace494b604b4c9"
integrity sha512-uOtts8NqDcaCt1rIsO3VFDRsAfgE4c6osG4d9z3l4dCBlxYFzni6Di/oNU270SDrjkfZuUvLZx1rxMyqh46Y9w==
dependencies:
data-uri-to-buffer "0.0.3"
parse-entities@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"
@@ -5763,6 +6000,11 @@ perfect-scrollbar@^1.5.5:
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz#41a211a2fb52a7191eff301432134ea47052b27f"
integrity sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g==
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
@@ -5804,6 +6046,11 @@ pluralize@^8.0.0:
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
pngjs@^3.3.3:
version "3.4.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
postcss-calc@^8.2.3:
version "8.2.4"
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5"
@@ -6171,6 +6418,11 @@ proxy-from-env@^1.1.0:
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
psl@^1.1.28:
version "1.9.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
pull-refresh-vue3@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/pull-refresh-vue3/-/pull-refresh-vue3-0.3.1.tgz#e75ffad5d71e30a85b5338f2beca9fc8a1e01432"
@@ -6189,6 +6441,11 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
punycode@^2.1.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
purgecss@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-5.0.0.tgz#08526ba3fef95e42c54503ca59d3f2ee8d6e5189"
@@ -6206,6 +6463,11 @@ qs@6.11.0:
dependencies:
side-channel "^1.0.4"
qs@~6.5.2:
version "6.5.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@@ -6358,6 +6620,32 @@ regjsparser@^0.9.1:
dependencies:
jsesc "~0.5.0"
request@^2.44.0:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.3"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.5.0"
tunnel-agent "^0.6.0"
uuid "^3.3.2"
require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
@@ -6430,7 +6718,7 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
safe-buffer@5.2.1, safe-buffer@^5.1.0:
safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -6451,7 +6739,7 @@ safe-regex@^2.1.1:
dependencies:
regexp-tree "~0.1.1"
"safer-buffer@>= 2.1.2 < 3":
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -6642,6 +6930,21 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5"
integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==
sshpk@^1.7.0:
version "1.18.0"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028"
integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
bcrypt-pbkdf "^1.0.0"
dashdash "^1.12.0"
ecc-jsbn "~0.1.1"
getpass "^0.1.1"
jsbn "~0.1.0"
safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
stable@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
@@ -7109,6 +7412,11 @@ thenify-all@^1.0.0:
dependencies:
any-promise "^1.0.0"
through@^2.3.4:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
tiny-glob@^0.2.9:
version "0.2.9"
resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.9.tgz#2212d441ac17928033b110f8b3640683129d31e2"
@@ -7134,6 +7442,14 @@ toidentifier@1.0.1:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
tough-cookie@~2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
dependencies:
psl "^1.1.28"
punycode "^2.1.1"
tr46@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
@@ -7183,6 +7499,18 @@ tsutils@^3.21.0:
dependencies:
tslib "^1.8.1"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==
dependencies:
safe-buffer "^5.0.1"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@@ -7304,6 +7632,11 @@ unimport@^3.0.6:
strip-literal "^1.0.1"
unplugin "^1.3.1"
uniq@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
integrity sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==
unique-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
@@ -7411,6 +7744,11 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
v8-compile-cache@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
@@ -7429,6 +7767,15 @@ vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
vite-plugin-pages@^0.29.0:
version "0.29.0"
resolved "https://registry.yarnpkg.com/vite-plugin-pages/-/vite-plugin-pages-0.29.0.tgz#8a7352cbbbc463fd2a725d67e221af8de8992c2f"