90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
// app/api/book/chapter/[id]/route.ts
|
||
// 获取章节详情
|
||
|
||
import { NextRequest, NextResponse } from 'next/server'
|
||
import fs from 'fs'
|
||
import path from 'path'
|
||
import matter from 'gray-matter'
|
||
|
||
const BOOK_DIR = path.join(process.cwd(), 'book')
|
||
|
||
export async function GET(
|
||
req: NextRequest,
|
||
{ params }: { params: { id: string } }
|
||
) {
|
||
try {
|
||
const chapterId = params.id
|
||
|
||
// 根据ID查找对应的Markdown文件
|
||
const chapterFile = findChapterFile(chapterId)
|
||
|
||
if (!chapterFile) {
|
||
return NextResponse.json(
|
||
{ error: '章节不存在' },
|
||
{ status: 404 }
|
||
)
|
||
}
|
||
|
||
const fileContent = fs.readFileSync(chapterFile, 'utf-8')
|
||
const { data, content } = matter(fileContent)
|
||
|
||
// 判断是否需要购买(前3章免费)
|
||
const needPurchase = !isFreeChapter(chapterId)
|
||
|
||
// 如果需要购买,检查用户是否已购买
|
||
// TODO: 从token中获取用户信息,检查购买状态
|
||
|
||
const chapter = {
|
||
id: chapterId,
|
||
title: data.title || path.basename(chapterFile, '.md'),
|
||
content: content,
|
||
words: content.length,
|
||
updateTime: data.date || fs.statSync(chapterFile).mtime.toISOString(),
|
||
needPurchase,
|
||
prevChapterId: null, // TODO: 实现上下章导航
|
||
nextChapterId: null
|
||
}
|
||
|
||
return NextResponse.json(chapter)
|
||
} catch (error) {
|
||
console.error('获取章节失败:', error)
|
||
return NextResponse.json(
|
||
{ error: '获取章节失败' },
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|
||
|
||
// 查找章节文件
|
||
function findChapterFile(chapterId: string): string | null {
|
||
const categories = fs.readdirSync(BOOK_DIR).filter(item => {
|
||
const itemPath = path.join(BOOK_DIR, item)
|
||
return fs.statSync(itemPath).isDirectory()
|
||
})
|
||
|
||
for (const category of categories) {
|
||
const categoryPath = path.join(BOOK_DIR, category)
|
||
const files = fs.readdirSync(categoryPath).filter(file => file.endsWith('.md'))
|
||
|
||
for (const file of files) {
|
||
const slug = `${category}/${file.replace('.md', '')}`
|
||
if (slug === chapterId || file.replace('.md', '') === chapterId) {
|
||
return path.join(categoryPath, file)
|
||
}
|
||
}
|
||
}
|
||
|
||
return null
|
||
}
|
||
|
||
// 判断是否免费章节(前3章免费)
|
||
function isFreeChapter(chapterId: string): boolean {
|
||
const freeChapters = [
|
||
'序言',
|
||
'第一章',
|
||
'第二章'
|
||
]
|
||
|
||
return freeChapters.some(free => chapterId.includes(free))
|
||
}
|