Skip to content

Commit

Permalink
feat(app): move resource detail page
Browse files Browse the repository at this point in the history
  • Loading branch information
yjl9903 committed Jan 16, 2024
1 parent 310259f commit 7f7427d
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 180 deletions.
6 changes: 4 additions & 2 deletions packages/animegarden/src/garden/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import type { Resource, ResourceDetail } from '../types';
import type {
ResolvedFilterOptions,
FetchResourcesOptions,
FetchResourceDetailOptions
FetchResourceDetailOptions,
ProviderType
} from './types';

import { retryFn } from './utils';
Expand Down Expand Up @@ -170,11 +171,12 @@ export async function fetchResources(

export async function fetchResourceDetail(
fetch: (request: RequestInfo, init?: RequestInit) => Promise<Response>,
provider: ProviderType,
href: string,
options: FetchResourceDetailOptions = {}
): Promise<(ResourceDetail & { id: number }) | undefined> {
const { baseURL = DefaultBaseURL, retry = 1 } = options;
const url = new URL('resource/' + href, baseURL);
const url = new URL(`detail/${provider}/${href}`, baseURL);

const resp = await retryFn(
() => fetch(url.toString(), { signal: options.signal }).then((r) => r.json()),
Expand Down
2 changes: 2 additions & 0 deletions packages/animegarden/src/garden/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Resource } from '../types';

export type ProviderType = 'dmhy' | 'moe';

export interface FilterOptions {
/**
* Only filter resources in the specific provider
Expand Down
2 changes: 1 addition & 1 deletion packages/app/astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default defineConfig({
policy: [
{
userAgent: '*',
allow: ['/resource/', '/anime/', '/docs/'],
allow: ['/detail/', '/resource/', '/anime/', '/docs/'],
disallow: ['/resources/', '/api/']
}
]
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/components/ResourceTable.astro
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ const search = Astro.url.searchParams;
function getMirrorHref(r: Resource) {
// @ts-ignore
if (r.id) return `/resource/${r.id}`;
return `/resource/${r.href.split('/').at(-1)}`;
if (r.id) return `/detail/${r.provider}/${r.id}`;
return `/detail/${r.provider}/${r.href.split('/').at(-1)}`;
}
function followSearch(params: Record<string, string>) {
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/components/Search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ export default function Search() {
<Command.Item
key={r.href}
value={r.href}
onMouseDown={selectStatic(`/resource/${r.href.split('/').at(-1)}`)}
onSelect={selectStatic(`/resource/${r.href.split('/').at(-1)}`)}
onMouseDown={selectStatic(`/detail/${r.provider}/${r.providerId}`)}
onSelect={selectStatic(`/detail/${r.provider}/${r.providerId}`)}
>
{r.title}
</Command.Item>
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/components/Search/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export function resolveSearchURL(search: string) {
} else {
const match = DMHY_RE.exec(search);
if (match) {
return `/resource/${match[1]}`;
return `/detail/dmhy/${match[1]}`;
} else {
const url = stringifySearchURL(location.origin, parseSearch(search));
return `${url.pathname}${url.search}`;
Expand Down
12 changes: 11 additions & 1 deletion packages/app/src/components/Swagger/spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,24 @@
}
}
},
"/resource/{href}": {
"/detail/{provider}/{href}": {
"get": {
"tags": [
"Resource"
],
"summary": "",
"description": "",
"parameters": [
{
"name": "provider",
"in": "path",
"description": "ID of Resource to return",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
},
{
"name": "href",
"in": "path",
Expand Down
7 changes: 4 additions & 3 deletions packages/app/src/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { APP_HOST, WORKER_HOST, SERVER_HOST, SERVER_PORT, SERVER_PROTOCOL } from '~build/meta';

import {
FilterOptions,
type ProviderType,
type FilterOptions,
fetchResources as rawFetchResources,
fetchResourceDetail as rawFetchResourceDetail
} from 'animegarden';
Expand Down Expand Up @@ -63,9 +64,9 @@ export async function fetchResources(
});
}

export async function fetchResourceDetail(href: string) {
export async function fetchResourceDetail(provider: string, href: string) {
try {
return await rawFetchResourceDetail(ofetch, href, {
return await rawFetchResourceDetail(ofetch, provider as ProviderType, href, {
baseURL
});
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const search = Astro.url.searchParams;
const feed = `/feed.xml?filter=${generateFeed(Astro.url.searchParams)}`;
const page = Astro.params.page ?? Astro.url.searchParams.get('page') ?? '1';
const enableFeed = page === '1' && !Astro.url.pathname.startsWith('/resource/');
const enableFeed = page === '1' && !Astro.url.pathname.startsWith('/detail/');
const env = getRuntimeEnv(Astro.locals);
const timestamp =
Expand Down Expand Up @@ -75,7 +75,7 @@ function followSearch(params: Record<string, string>) {

<link rel="sitemap" href="/sitemap-index.xml" />
{
!url.startsWith('/resource/') && (
!url.startsWith('/detail/') && (
<link rel="alternate" type="application/rss+xml" title="RSS Feeds" href={feed} />
)
}
Expand Down
167 changes: 167 additions & 0 deletions packages/app/src/pages/detail/[provider]/[href].astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
import { APP_HOST } from '~build/meta';
import { parse } from 'anitomy';
import { formatInTimeZone } from 'date-fns-tz';
import Layout from '@/layouts/Layout.astro';
import { fetchResourceDetail } from '@/fetch';
const { href, provider } = Astro.params;
if (!href || !/^\d+/.test(href) || !provider || !['dmhy', 'moe'].includes(provider)) {
return Astro.redirect('/');
}
const detail = await fetchResourceDetail(provider, href);
if (!detail) {
return Astro.redirect('/');
}
const files = detail.magnet.files.filter((f) => f.size !== '種子可能不存在' && f.size !== 'Bytes');
const info = parse(detail.title);
const schema = info
? JSON.stringify({
'@context': 'http://schema.org',
'@type': 'TVEpisode',
partOfTVSeries: {
'@type': 'TVSeries',
name: info.title
},
partOfSeason: {
'@type': 'TVSeason',
seasonNumber: `${info.season ?? 1}`
},
episodeNumber: info.episode.number !== undefined ? `${info.episode.number}` : undefined,
datePublished: detail.createdAt,
url: Astro.url.toString()
})
: undefined;
---

<Layout title={`${detail.title}`}>
<div class="detail mt-4vh w-full space-y-4">
<h3 class="text-xl font-bold">
<span>{detail.title}</span>
</h3>
<div class="download-link rounded-md shadow-box">
<h4 class="text-lg font-bold border-b px4 py2">
<a href={detail.magnet.href} class="text-link-active">下载链接</a>
</h4>
<div
class="p4 space-y-1 overflow-auto whitespace-nowrap [&>div>span]:(text-base-600 select-none inline-block w-[160px] min-w-[160px]) [&>div]:(flex) [&>div>a]:(inline-block flex-1)"
>
<div>
<span>原链接</span>
<a href={detail.href} target="_blank" class="text-link">{detail.href}</a>
</div>
<div>
<span>会员链接</span>
<a href={detail.magnet.user} class="text-link">{detail.magnet.user}</a>
</div>
<div>
<span>Magnet 链接</span>
<a href={detail.magnet.href} class="text-link">{detail.magnet.href.split('&')[0]}</a>
</div>
<div>
<span>Magnet 链接 type II</span>
<a href={detail.magnet.href2} class="text-link">{detail.magnet.href2}</a>
</div>
<!-- <div>
<span>弹幕播放链接</span>
<a href={detail.magnet.ddplay} class="text-link">{detail.magnet.ddplay}</a>
</div> -->
</div>
</div>

<div
class="description"
set:html={detail.description.replace(
/簡介:(&nbsp;)?/,
'<h4 class="text-lg font-bold">简介</h4>'
)}
/>

<div class="publisher">
<h4 class="text-lg font-bold pb4">
{detail.fansub ? '发布者 / 字幕组' : '发布者'}
</h4>
<div class="flex gap8">
<div>
<a href={`/resources/1?publisherId=${detail.publisher.id}`} class="block text-left">
<img
src={detail.publisher.avatar}
alt="Publisher Avatar"
onerror="this.src = `https://share.dmhy.org/images/defaultUser.png`;"
class="inline-block w-[100px] h-[100px] rounded"
/>
<span class="text-link block mt2">{detail.publisher.name}</span>
</a>
</div>
{
detail.fansub && (
<div>
<a href={`/resources/1?fansubId=${detail.fansub.id}`} class="block w-auto text-left">
<img
src={detail.fansub.avatar}
alt="Fansub Avatar"
onerror="this.src = `https://share.dmhy.org/images/defaultUser.png`;"
class="inline-block w-[100px] h-[100px] rounded"
/>
<span class="text-link block mt2">{detail.fansub.name}</span>
</a>
</div>
)
}
</div>
</div>
<div>
<span class="font-bold">发布于&nbsp;</span><span
>{formatInTimeZone(new Date(detail.createdAt), 'Asia/Shanghai', 'yyyy-MM-dd HH:mm')}</span
>
</div>
<div class="file-list rounded-md shadow-box">
<h4 class="text-lg font-bold border-b px4 py2">文件列表</h4>
<div class="mb4 max-h-[80vh] overflow-auto px4">
{
files.map((f) => (
<div class="py2 flex justify-between items-center gap4">
<div class="text-sm text-base-600">{f.name}</div>
<div class="text-xs text-base-400 select-none">{f.size}</div>
</div>
))
}
{
files.length === 0 ? (
<div class="py2 select-none text-center text-red-400">种子信息解析失败</div>
) : undefined
}
{detail.magnet.hasMoreFiles ? <div class="text-base-400">...</div> : undefined}
</div>
</div>
</div>
</Layout>

{info && <script type="application/ld+json" set:html={schema} />}

<style is:global>
.detail .description hr {
margin-top: 0.5rem;
padding-bottom: 0.5rem;
}

.detail .description img {
margin-bottom: 0.5rem;
max-width: 60%;
max-height: 60vh;
border-radius: 4px;
object-fit: cover;
}

@media (max-width: 767.9px) {
.detail .description img {
max-width: 90%;
max-height: 80vh;
}
}
</style>
Loading

0 comments on commit 7f7427d

Please sign in to comment.