blob: 0cb738cb272ca1d8a543771dd680089695a4da9e [file] [log] [blame]
223010095b28c672025-04-10 20:12:45 +08001import React, { useEffect, useState } from 'react';
2import axios from 'axios';
2230100980aaf0d2025-06-05 23:20:05 +08003import { useParams } from 'wouter';
223010095b28c672025-04-10 20:12:45 +08004import Header from '../../../components/Header';
5import './SeedDetail.css';
2230100980aaf0d2025-06-05 23:20:05 +08006import { useUser } from '../../../context/UserContext';
Krishya2283d882025-05-27 22:25:19 +08007
223010095b28c672025-04-10 20:12:45 +08008const SeedDetail = () => {
2230100980aaf0d2025-06-05 23:20:05 +08009 const params = useParams();
10 const seed_id = params.id;
223010095b28c672025-04-10 20:12:45 +080011
2230100980aaf0d2025-06-05 23:20:05 +080012 const [seed, setSeed] = useState(null);
13 const [coverImage, setCoverImage] = useState(null);
14 const [error, setError] = useState(null);
15 const [comments, setComments] = useState([]);
16 const [newComment, setNewComment] = useState('');
17
18 const { user } = useUser();
19
2230100980aaf0d2025-06-05 23:20:05 +080020 const formatImageUrl = (url) => {
21 if (!url) return '';
22 const filename = url.split('/').pop();
223010094158f3a2025-06-06 19:59:10 +080023 return `http://localhost:5011/uploads/torrents/${filename}`;
2230100980aaf0d2025-06-05 23:20:05 +080024 };
25
26 useEffect(() => {
27 if (!seed_id) {
28 setError('无效的种子ID');
29 return;
30 }
31
32 const fetchSeedDetail = async () => {
33 try {
34 const res = await axios.post(`/seeds/info/${seed_id}`);
35 if (res.data.code === 0) {
36 const seedData = res.data.data;
2230100980aaf0d2025-06-05 23:20:05 +080037 let cover = seedData.imageUrl;
38 if (!cover && seedData.imgUrl) {
39 const imgs = seedData.imgUrl
40 .split(',')
41 .map((i) => i.trim())
42 .filter(Boolean);
43 cover = imgs.length > 0 ? formatImageUrl(imgs[0]) : null;
44 }
45 setCoverImage(cover);
46 setSeed(seedData);
47 setError(null);
48 } else {
49 setError('未能获取种子信息');
50 }
51 } catch (err) {
52 console.error('请求种子详情出错:', err);
53 setError('获取种子详情失败');
54 }
55 };
56
57 const fetchComments = async () => {
58 try {
59 const res = await axios.get(`/seeds/${seed_id}/comments`);
60 if (res.data.code === 0) {
61 setComments(res.data.data || []);
62 } else {
63 setComments([]);
64 }
65 } catch {
66 setComments([]);
67 }
68 };
69
70 fetchSeedDetail();
71 fetchComments();
72 }, [seed_id]);
73
223010094952a0f2025-06-07 18:58:16 +080074 const handleDownload = async (seedId) => {
75 if (!user || !user.userId) {
76 alert('请先登录再下载种子文件');
77 return;
78 }
2230100980aaf0d2025-06-05 23:20:05 +080079
223010094952a0f2025-06-07 18:58:16 +080080 try {
81 const response = await axios.get(`/seeds/${seedId}/download`, {
82 params: { passkey: user.userId },
83 responseType: 'blob',
84 });
Krishyac0f7e9b2025-04-22 15:28:28 +080085
223010094952a0f2025-06-07 18:58:16 +080086 const blob = new Blob([response.data], { type: 'application/x-bittorrent' });
87 const downloadUrl = URL.createObjectURL(blob);
88 const a = document.createElement('a');
89 a.href = downloadUrl;
90 a.download = `${seedId}.torrent`;
91 a.click();
92 URL.revokeObjectURL(downloadUrl);
93 } catch (error) {
94 console.error('下载失败:', error);
95 alert('下载失败,请稍后再试。');
96 }
2230100980aaf0d2025-06-05 23:20:05 +080097 };
Krishyac0f7e9b2025-04-22 15:28:28 +080098
223010094952a0f2025-06-07 18:58:16 +080099 const handleCollect = async () => {
100 if (!user || !user.userId) {
101 alert('请先登录再收藏');
102 return;
103 }
104
105 try {
106 const res = await axios.post(`/seeds/${seed.id}/favorite-toggle`, null, {
107 params: { user_id: user.userId },
108 });
109
110 if (res.data.code === 0) {
111 alert('操作成功');
112 } else {
113 alert(res.data.msg || '操作失败');
114 }
115 } catch (err) {
116 console.error('收藏失败:', err);
117 alert('收藏失败,请稍后再试。');
118 }
119 };
120
121 const handleAddComment = async () => {
122 if (!user || !user.userId) {
123 alert('请登录后发表评论');
124 return;
125 }
126
2230100980aaf0d2025-06-05 23:20:05 +0800127 if (newComment.trim()) {
223010094952a0f2025-06-07 18:58:16 +0800128 try {
129 const res = await axios.post(`/seeds/${seed_id}/comments`, {
130 user_id: user.userId,
131 content: newComment,
132 });
133
134 if (res.data.code === 0) {
135 setComments([...comments, { content: newComment, user: user.username || '匿名用户' }]);
136 setNewComment('');
137 } else {
138 alert(res.data.msg || '评论失败');
139 }
140 } catch (err) {
141 console.error('评论提交失败:', err);
142 alert('评论失败,请稍后重试');
143 }
Krishyac0f7e9b2025-04-22 15:28:28 +0800144 }
2230100980aaf0d2025-06-05 23:20:05 +0800145 };
Krishyac0f7e9b2025-04-22 15:28:28 +0800146
2230100980aaf0d2025-06-05 23:20:05 +0800147 if (error) {
223010095b28c672025-04-10 20:12:45 +0800148 return (
2230100980aaf0d2025-06-05 23:20:05 +0800149 <div className="seed-detail-page">
150 <Header />
151 <div className="seed-detail">
152 <p className="error-text">{error}</p>
223010095b28c672025-04-10 20:12:45 +0800153 </div>
2230100980aaf0d2025-06-05 23:20:05 +0800154 </div>
223010095b28c672025-04-10 20:12:45 +0800155 );
2230100980aaf0d2025-06-05 23:20:05 +0800156 }
157
158 if (!seed) {
159 return (
160 <div className="seed-detail-page">
161 <Header />
162 <div className="seed-detail">
163 <p>加载中...</p>
164 </div>
165 </div>
166 );
167 }
168
223010094952a0f2025-06-07 18:58:16 +0800169 const tags = Array.isArray(seed.tags)
170 ? seed.tags
171 : typeof seed.tags === 'string'
172 ? seed.tags.split(',').map((t) => t.trim())
2230100980aaf0d2025-06-05 23:20:05 +0800173 : [];
174
223010094952a0f2025-06-07 18:58:16 +0800175 const actors = Array.isArray(seed.actors)
176 ? seed.actors
177 : typeof seed.actors === 'string'
178 ? seed.actors.split(',').map((a) => a.trim())
2230100980aaf0d2025-06-05 23:20:05 +0800179 : [];
180
181 return (
182 <div className="seed-detail-page">
183 <Header />
184 <div className="seed-detail">
185 <h1>{seed.title}</h1>
186 <div className="seed-header-container">
187 <div className="seed-info">
188 <div className="seed-basic-info">
189 <p><strong>分类:</strong>{seed.category || '未知'}</p>
190 <p><strong>发布时间:</strong>{seed.upload_time ? new Date(seed.upload_time).toLocaleString() : '未知'}</p>
191 <p><strong>标签:</strong>{tags.join(' / ')}</p>
192 <p><strong>简介:</strong>{seed.description || ''}</p>
193 <p><strong>大小:</strong>{seed.size || '未知'}</p>
194 <p><strong>分辨率:</strong>{seed.resolution || '未知'}</p>
195 <p><strong>片长:</strong>{seed.duration || '未知'}</p>
196 <p><strong>地区:</strong>{seed.region || '未知'}</p>
197 <p><strong>下载次数:</strong>{seed.downloads ?? 0}</p>
198 </div>
199 {(seed.category === '电影' || seed.category === '电视剧') && (
200 <div className="seed-media-info">
201 <p><strong>导演:</strong>{seed.director || '未知'}</p>
202 <p><strong>编剧:</strong>{seed.writer || '未知'}</p>
203 <p><strong>主演:</strong>{actors.join(' / ')}</p>
204 </div>
205 )}
206 </div>
207 <img
208 src={coverImage || '/default-cover.png'}
209 alt={seed.title}
210 className="cover-image"
211 />
212 </div>
223010094952a0f2025-06-07 18:58:16 +0800213
2230100980aaf0d2025-06-05 23:20:05 +0800214 <div className="action-buttons">
215 <button className="btn" onClick={() => handleDownload(seed.id)}>下载</button>
223010094952a0f2025-06-07 18:58:16 +0800216 <button className="btn-outline" onClick={handleCollect}>收藏</button>
2230100980aaf0d2025-06-05 23:20:05 +0800217 </div>
223010094952a0f2025-06-07 18:58:16 +0800218
2230100980aaf0d2025-06-05 23:20:05 +0800219 <hr className="divider" />
220 <h3>评论区</h3>
221 <div className="comments-section">
222 <div className="comments-list">
223010094952a0f2025-06-07 18:58:16 +0800223 {comments.length === 0 ? (
224 <p className="no-comments">暂无评论</p>
225 ) : (
226 comments.map((comment, index) => (
227 <div key={index} className="comment">
228 <p className="comment-user">{comment.user}</p>
229 <p className="comment-content">{comment.content}</p>
230 </div>
231 ))
232 )}
2230100980aaf0d2025-06-05 23:20:05 +0800233 </div>
234 <div className="add-comment-form">
235 <textarea
236 placeholder="输入你的评论..."
237 value={newComment}
238 onChange={(e) => setNewComment(e.target.value)}
239 />
240 <div className="comment-options">
241 <button className="btn" onClick={handleAddComment}>发布评论</button>
242 </div>
243 </div>
244 </div>
245 </div>
246 </div>
247 );
223010095b28c672025-04-10 20:12:45 +0800248};
249
250export default SeedDetail;