add search pages

This commit is contained in:
jxxghp
2023-07-07 17:40:43 +08:00
parent e8372b8566
commit 9104a25652
8 changed files with 276 additions and 7 deletions

View File

@@ -47,4 +47,23 @@ export const formatDateToMonthShort = (value: string, toTimeForCurrentDay = true
export const prefixWithPlus = (value: number) => value > 0 ? `+${value}` : value
// 格式化为Sxx
export const formatSeason = (value: string) => value ? `S${value.padStart(2, '0')}` : ''
// 格式化为xx[TGMK]B
export const formatFileSize = (bytes: number) => {
if (bytes < 0) {
throw new Error("字节数不能为负数。");
}
const units = ["B", "KB", "MB", "GB", "TB"];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
}

View File

@@ -1,3 +1,4 @@
// 订阅
export interface Subscribe {
id: number;
@@ -253,3 +254,140 @@ export interface Plugin {
installed?: boolean
}
// 种子信息
export interface TorrentInfo {
// 站点ID
site?: number
// 站点名称
site_name?: string
// 站点Cookie
site_cookie?: string
// 站点UA
site_ua?: string
// 站点是否使用代理
site_proxy: boolean
// 站点优先级
site_order: number
// 种子名称
title?: string
// 种子副标题
description?: string
// IMDB ID
imdbid: string
// 种子链接
enclosure?: string
// 详情页面
page_url?: string
// 种子大小
size: number
// 做种者
seeders: number
// 下载者
peers: number
// 完成者
grabs: number
// 发布时间
pubdate?: string
// 已过时间
date_elapsed?: string
// 上传因子
uploadvolumefactor: number
// 下载因子
downloadvolumefactor: number
// HR
hit_and_run: boolean
// 种子标签
labels: string[]
// 种子优先级
pri_order: number
}
// 识别元数据
export interface MetaInfo {
// 是否处理的文件
isfile: boolean
// 原字符串
org_string?: string
// 副标题
subtitle?: string
// 类型 电影、电视剧
type: string
// 识别的中文名
cn_name?: string
// 识别的英文名
en_name?: string
// 年份
year?: string
// 总季数
total_seasons: number
// 识别的开始季 数字
begin_season?: number
// 识别的结束季 数字
end_season?: number
// 总集数
total_episodes: number
// 识别的开始集
begin_episode?: number
// 识别的结束集
end_episode?: number
// Partx Cd Dvd Disk Disc
part?: string
// 识别的资源类型
resource_type?: string
// 识别的效果
resource_effect?: string
// 识别的分辨率
resource_pix?: string
// 识别的制作组/字幕组
resource_team?: string
// 视频编码
video_encode?: string
// 音频编码
audio_encode?: string
// 名称(自动中英文)
name: string
// SXX-SXX
season: string
// SXX-SXX 有季号才返回
sea: string
// begin_season 的数字电视剧没有季的返回1
season_seq: string
// 季的数组
season_list: number[]
// Exx-Exx
episode: string
// 集的数组
episode_list: number[]
// ExxExx
episodes: string
//xx-xx
episode_seqs: string
// begin_episode 的数字
episode_seq: string
// SxxExx
season_episode: string
// 资源类型字符串,含分辨率
resource_term: string
// 资源类型字符串,不含分辨率
edtion: string
// 发布组/字幕组字符串
release_group: string
// 视频编码
video_term: string
// 音频编码
audio_term: string
}
// 上下文信息
export interface Context {
// 元信息
meta_info: MetaInfo,
// 媒体信息
media_info: MediaInfo,
// 种子信息
torrent_info: TorrentInfo,
}

View File

@@ -3,8 +3,8 @@ import { formatSeason } from "@/@core/utils/formatters";
import api from "@/api";
import { doneNProgress, startNProgress } from "@/api/nprogress";
import { MediaInfo, NotExistMediaInfo, Subscribe, TmdbSeason } from "@/api/types";
import router from "@/router";
import { useToast } from "vue-toast-notification";
// 输入参数
const props = defineProps({
media: Object as PropType<MediaInfo>,
@@ -231,7 +231,7 @@ const checkSeasonsNotExists = async () => {
});
}
} catch (error) {
$toast.error(`${props.media?.title}无法识别到themoviedb媒体信息!`);
$toast.error(`${props.media?.title}无法识别TMDB媒体信息!`);
tmdbFlag.value = false;
}
// 处理完成
@@ -318,6 +318,17 @@ const openDetailWindow = () => {
window.open(getDetailLink(), "_blank");
};
// 开始搜索
const handleSearch = () => {
router.push(
`/resource/${
props.media?.tmdb_id
? `tmdb:${props.media?.tmdb_id}`
: `douban:${props.media?.douban_id}`
}`
);
};
// 装载时检查是否已订阅
onBeforeMount(handleCheckSubscribe);
@@ -394,7 +405,7 @@ const seasonsSelected = ref<TmdbSeason[]>([]);
{{ props.media?.overview }}
</p>
<div class="flex align-center justify-between">
<IconBtn icon="mdi-magnify" color="white" />
<IconBtn icon="mdi-magnify" color="white" @click.stop="handleSearch" />
<IconBtn
icon="mdi-heart"
:color="isSubscribed ? 'error' : 'white'"

View File

@@ -0,0 +1,21 @@
<script lang="ts" setup>
import { Context } from "@/api/types";
// 输入参数
const props = defineProps({
torrent: Object as PropType<Context>,
width: String,
height: String,
});
</script>
<template>
<VCard :width="props.width" :height="props.height">
<VCardItem>
<VCardTitle>{{ props.torrent?.torrent_info.title }}</VCardTitle>
</VCardItem>
<VCardText>
{{ props.torrent?.torrent_info.description }}
</VCardText>
</VCard>
</template>

View File

@@ -1,3 +1,16 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import TorrentCardListView from "@/views/discover/TorrentCardListView.vue";
<template></template>
// 路由参数
const route = useRoute();
// 查询TMDBID或标题
const keyword = route.params?.keyword?.toString() ?? "";
console.log(keyword);
</script>
<template>
<div>
<TorrentCardListView :keyword="keyword" />
</div>
</template>

View File

@@ -27,8 +27,9 @@ const router = createRouter({
},
},
{
path: 'resource',
path: 'resource/:keyword+',
component: () => import('../pages/resource.vue'),
props: true,
meta: {
requiresAuth: true,
},

View File

@@ -0,0 +1,66 @@
<script lang="ts" setup>
import api from "@/api";
import { Context } from "@/api/types";
import TorrentCard from "@/components/cards/TorrentCard.vue";
import NoDataFound from "@/components/NoDataFound.vue";
// 定义输入参数
const props = defineProps({
keyword: String,
});
// 数据列表
const dataList = ref<Context[]>([]);
// 是否刷新过
const isRefreshed = ref(false);
// 获取订阅列表数据
const fetchData = async () => {
try {
// 优先按TMDBID精确查询
if (props.keyword?.startsWith("tmdb:") || props.keyword?.startsWith("douban:")) {
dataList.value = await api.get(`search/media/${props.keyword}`);
} else {
// 按标题模糊查询
dataList.value = await api.get(`search/title/${props.keyword}`);
}
isRefreshed.value = true;
} catch (error) {
console.error(error);
}
};
// 加载时获取数据
onBeforeMount(fetchData);
</script>
<template>
<VProgressCircular
class="centered"
v-if="!isRefreshed"
indeterminate
color="primary"
></VProgressCircular>
<div class="grid gap-3 grid-torrent-card" v-if="dataList.length > 0">
<TorrentCard
v-for="data in dataList"
:key="data.torrent_info.title"
:torrent="data"
/>
</div>
<NoDataFound
v-if="dataList.length === 0 && isRefreshed"
error-code="404"
error-title="没有资源"
error-description="没有搜索到符合条件的资源"
>
</NoDataFound>
</template>
<style type="scss">
.grid-torrent-card {
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
padding-block-end: 1rem;
}
</style>

View File

@@ -31,7 +31,7 @@ onBeforeMount(fetchData);
indeterminate
color="primary"
></VProgressCircular>
<div class="grid gap-3 grid-site-card" v-if="dataList.length > 0">
<div class="grid gap-3 grid-plugin-card" v-if="dataList.length > 0">
<PluginCard v-for="data in dataList" :key="data.id" :plugin="data" />
</div>
<NoDataFound