mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-08 14:26:37 +08:00
feat: Emby 兼容层完整实现 + 多模块功能增强
## Emby/Jellyfin 兼容层 (emby_compat.go / emby.go) - 新增 SystemInfoPublic、FindUser、Items、Item、LatestItems、ResumeItems - 新增 SetFavorite、MarkPlayed、RecordProgress 用户播放状态同步 - 新增 itemPayload、mediaSource、mediaStreams 媒体信息组装 - 双前缀路由 /emby/* 和 / 根路径,兼容 Infuse/Yamby/Senplayer/Kodi - 新增 Ping、SystemEndpoint、AuthByName 端点 - emby.go 扩展对应 handler 函数 ## 站点适配器 (site_adapter.go / site.go) - SiteConfig 扩展 UserAgent/Timeout/Extra/FlareSolverrURL 字段 - doRequest() GET 请求支持 FlareSolverr 代理绕过 Cloudflare/WAF - MTeam api_key 认证改为 Authorization: Bearer 格式 - Search() 重构为 sync.WaitGroup 并发执行,提升多站搜索性能 - siteModelToConfig() 改为 SiteService 方法,按 BrowserEmulation 填充 FlareSolverrURL ## 图片代理 (image_proxy.go) - 重构图片代理服务,支持更多来源和缓存策略 ## 下载管理 (downloads.go / download_clients.go / qbittorrent.go) - 下载任务增强:状态管理、进度追踪优化 - qBittorrent 客户端连接稳定性改进 ## 刮削与数据库 (scraper.go / tmdb.go / repository.go) - 刮削器增强 TMDB 集成,补全元数据字段 - repository 扩展查询方法 ## 前端 (web/src/) - HomePage: 首页布局重构,按媒体库分组展示,系列聚合优化 - DiscoverPage: 发现页增强,错误处理改进(API key 缺失/网络错误分离) - PosterWallPage: 海报墙优化,系列聚合展示 - MediaCard: 媒体卡片优化 - PlayerPage: 播放器改进 - 新增 utils/groupSeries.ts: 系列聚合工具函数 - .gitignore: 添加 .tmp_* 临时文件排除规则
This commit is contained in:
@@ -1,24 +1,28 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { GalleryHorizontalEnd } from 'lucide-react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { GalleryHorizontalEnd, Layers } from 'lucide-react'
|
||||
|
||||
import { mediaAPI } from '../api/library'
|
||||
import { MediaCard } from '../components/MediaCard'
|
||||
import { groupSeries } from '../utils/groupSeries'
|
||||
import type { Media } from '../types'
|
||||
|
||||
// PosterWallPage shows a dense poster grid of all media across every
|
||||
// library — a visual "poster wall" that matches the original MediaStation's
|
||||
// PosterWallView.vue. Loads the first 200 items sorted by rating.
|
||||
// PosterWallPage 把所有媒体的代表海报聚合到同一面墙,便于一目了然
|
||||
// 浏览整个站点的内容。所有 episode 行会按剧集折叠,避免同一海报刷屏。
|
||||
export function PosterWallPage() {
|
||||
const [items, setItems] = useState<Media[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
// 拉得多一点(500),折叠后才能凑够展示量;后端 page_size 上限可能
|
||||
// 需要后续观察,暂以 500 试探。
|
||||
mediaAPI
|
||||
.search('', 200)
|
||||
.search('', 500)
|
||||
.then((d) => setItems(d.items))
|
||||
.finally(() => setLoading(false))
|
||||
}, [])
|
||||
|
||||
const cards = useMemo(() => groupSeries(items).slice(0, 240), [items])
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<header className="flex items-center gap-3">
|
||||
@@ -26,18 +30,26 @@ export function PosterWallPage() {
|
||||
<div>
|
||||
<h1 className="font-display text-3xl font-bold text-white">海报墙</h1>
|
||||
<p className="text-sm text-slate-400">
|
||||
全部媒体的海报展示(最多 200 项)。
|
||||
按剧集聚合 · 共 {cards.length} 个条目
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{loading && <p className="text-slate-500">加载中…</p>}
|
||||
{!loading && items.length === 0 && (
|
||||
{!loading && cards.length === 0 && (
|
||||
<p className="text-slate-400">暂无媒体。请先添加媒体库并扫描。</p>
|
||||
)}
|
||||
<div className="grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-8">
|
||||
{items.map((m) => (
|
||||
<MediaCard key={m.id} media={m} />
|
||||
<div className="grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10">
|
||||
{cards.map((s) => (
|
||||
<div key={s.rep.id} className="relative">
|
||||
<MediaCard media={s.rep} />
|
||||
{s.count > 1 && (
|
||||
<span className="pointer-events-none absolute right-1.5 top-1.5 inline-flex items-center gap-0.5 rounded-md bg-black/60 px-1.5 py-0.5 text-[10px] font-medium text-white backdrop-blur-sm">
|
||||
<Layers size={10} />
|
||||
{s.count}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user