Skip to content

Commit 46dc645

Browse files
author
pikachuren
committed
fix(media): allow guest media access, per-file local thumbnails and optional cover proxy
1 parent dcf74ad commit 46dc645

6 files changed

Lines changed: 19 additions & 13 deletions

File tree

‎internal/bootstrap/data/setting.go‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ func InitialSettings() []model.SettingItem {
277277
Help: `开启后提供 OpenSubsonic API(/rest),可供 Symfonium、Feishin、Amperfy 等音乐客户端接入`},
278278
{Key: conf.MediaSubsonicProxyStream, Value: "false", Type: conf.TypeBool, Group: model.MEDIA, Flag: model.PRIVATE,
279279
Help: `Subsonic 播放默认返回 302 直链;若客户端不跟随重定向,可开启此项改为服务端代理转发(占用服务器带宽)`},
280+
{Key: conf.MediaProxyCover, Value: "false", Type: conf.TypeBool, Group: model.MEDIA, Flag: model.PRIVATE,
281+
Help: `开启后由服务端代理 TMDB/豆瓣等外部封面图片,适合直连图片域名受限的网络;默认关闭,直接使用原始图片地址`},
280282
{Key: conf.MediaStrmOnScan, Value: "false", Type: conf.TypeBool, Group: model.MEDIA, Flag: model.PRIVATE,
281283
Help: `扫描完成后自动把媒体条目生成为 .strm 文件并写入下方目录`},
282284
{Key: conf.MediaStrmPath, Value: "/strm", Type: conf.TypeString, Group: model.MEDIA, Flag: model.PRIVATE,

‎internal/conf/const.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ const (
191191
MediaEmbyEnabled = "media_emby_enabled" // Emby 兼容 API 开关
192192
MediaSubsonicEnabled = "media_subsonic_enabled" // OpenSubsonic API 开关
193193
MediaSubsonicProxyStream = "media_subsonic_proxy_stream" // Subsonic 播放是否强制代理(兼容不跟随 302 的客户端)
194+
MediaProxyCover = "media_proxy_cover" // 是否通过服务端代理外部封面(TMDB/豆瓣等)
194195
MediaStrmOnScan = "media_strm_on_scan" // 扫描完成后自动生成 STRM
195196
MediaStrmPath = "media_strm_path" // STRM 输出目录(VFS 路径)
196197
MediaStrmOverwrite = "media_strm_overwrite" // 生成 STRM 时是否覆盖已存在文件

‎internal/media/scraper/book_local.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (s *BookLocalScraper) ScrapeBookLocal(item *model.MediaItem, reader io.Read
7979
coverData = extractPDFCoverData(data)
8080
}
8181
if len(coverData) > 0 {
82-
cover := s.storeCover(item.FolderPath, coverData)
82+
cover := s.storeCover(strings.TrimSuffix(item.FolderPath, "/")+"/"+item.FileName, coverData)
8383
if cover != "" {
8484
item.Cover = cover
8585
}

‎internal/media/scraper/image.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func (s *ImageScraper) ScrapeImage(item *model.MediaItem, reader io.Reader) erro
9090
// ── 2. 生成缩略图并存储 ──────────────────────────────────────
9191
if s.ThumbnailMode == "local" {
9292
// 本地存储模式:将缩略图保存到指定目录,Cover 存储本地路径
93-
if localPath := s.saveThumbnailLocal(item.FolderPath, data); localPath != "" {
93+
if localPath := s.saveThumbnailLocal(strings.TrimSuffix(item.FolderPath, "/")+"/"+item.FileName, data); localPath != "" {
9494
item.Cover = localPath
9595
}
9696
// 本地存储失败时 cover 保持为空,不降级为文件路径

‎server/handles/media_extra.go‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type MediaStatus struct {
2828
StrmPath string `json:"strm_path"`
2929
StrmOnScan bool `json:"strm_on_scan"`
3030
ThumbPath string `json:"thumb_path"`
31+
Version string `json:"version"`
32+
ProxyCover bool `json:"proxy_cover"`
3133
}
3234

3335
// PublicMediaStatus 公开的媒体库状态
@@ -38,6 +40,8 @@ func PublicMediaStatus(c *gin.Context) {
3840
status.StrmPath = media.DefaultStrmOptions(apiBase).OutputPath
3941
status.StrmOnScan = setting.GetBool(conf.MediaStrmOnScan)
4042
status.ThumbPath = setting.GetStr(conf.MediaThumbnailPath, "/imgs")
43+
status.Version = conf.Version
44+
status.ProxyCover = setting.GetBool(conf.MediaProxyCover)
4145
if !status.Enabled {
4246
common.SuccessResp(c, status)
4347
return

‎server/router.go‎

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,16 @@ func Init(e *gin.Engine) {
133133
g.Any("/rest/*path", handles.SubsonicAPI)
134134

135135
_fs(auth.Group("/fs"))
136+
// 媒体库公开 API:与文件浏览一致,允许访客访问(访客仍受自身 base_path/权限限制)
137+
mediaPublic := auth.Group("/fs/media", handles.RequireMediaEnabled)
138+
mediaPublic.GET("/list", handles.PublicListMedia)
139+
mediaPublic.GET("/item/:id", handles.PublicGetMedia)
140+
mediaPublic.GET("/albums", handles.PublicListAlbums)
141+
mediaPublic.GET("/album", handles.PublicGetAlbum)
142+
mediaPublic.GET("/folders", handles.PublicListFolders)
143+
mediaPublic.GET("/scan_paths", handles.PublicListScanPaths)
144+
mediaPublic.GET("/strm", handles.GetMediaStrm)
145+
mediaPublic.GET("/stream_url", handles.GetMediaStreamURL)
136146
fsAndShare(api.Group("/fs", middlewares.Auth(true)))
137147
_task(auth.Group("/task", middlewares.AuthNotGuest))
138148
_sharing(auth.Group("/share", middlewares.AuthNotGuest))
@@ -262,17 +272,6 @@ func fsAndShare(g *gin.RouterGroup) {
262272
a.Any("/meta", handles.FsArchiveMetaSplit)
263273
a.Any("/list", handles.FsArchiveListSplit)
264274

265-
// 媒体库公开API(媒体库关闭时整组 404)
266-
mediaPublic := g.Group("/media", handles.RequireMediaEnabled)
267-
mediaPublic.GET("/list", handles.PublicListMedia)
268-
mediaPublic.GET("/item/:id", handles.PublicGetMedia)
269-
mediaPublic.GET("/albums", handles.PublicListAlbums)
270-
mediaPublic.GET("/album", handles.PublicGetAlbum)
271-
mediaPublic.GET("/folders", handles.PublicListFolders)
272-
mediaPublic.GET("/scan_paths", handles.PublicListScanPaths)
273-
mediaPublic.GET("/strm", handles.GetMediaStrm)
274-
mediaPublic.GET("/stream_url", handles.GetMediaStreamURL)
275-
276275
// 转码 - 用户态:申请播放
277276
g.POST("/transcode/play", handles.RequireMediaEnabled, handles.TranscodePlay)
278277
}

0 commit comments

Comments
 (0)