66 "encoding/json"
77 "io"
88 "mime"
9- "net/http"
109 stdpath "path"
1110 "regexp"
1211 "strings"
@@ -19,7 +18,9 @@ import (
1918 "github.com/OpenListTeam/OpenList/v4/internal/db"
2019 "github.com/OpenListTeam/OpenList/v4/internal/fs"
2120 "github.com/OpenListTeam/OpenList/v4/internal/model"
21+ "github.com/OpenListTeam/OpenList/v4/internal/stream"
2222 "github.com/OpenListTeam/OpenList/v4/pkg/http_range"
23+ "github.com/OpenListTeam/OpenList/v4/pkg/utils"
2324)
2425
2526// 支持的文件扩展名
@@ -375,8 +376,8 @@ func doScanMusicByAlbum(ctx context.Context, targets []string, sp *model.MediaSc
375376 item := & model.MediaItem {
376377 MediaType : sp .MediaType ,
377378 ScanPathID : sp .ID ,
378- FileName : name , // 文件夹名
379- FolderPath : stdpath .Dir (target ), // 文件夹所在的真实父目录
379+ FileName : name , // 文件夹名
380+ FolderPath : stdpath .Dir (target ), // 文件夹所在的真实父目录
380381 IsFolder : true ,
381382 AlbumName : albumName ,
382383 AlbumArtist : albumArtist ,
@@ -485,8 +486,8 @@ func doScanMusicByAlbum(ctx context.Context, targets []string, sp *model.MediaSc
485486}
486487
487488// loadLyricsForMusic 为音乐文件加载歌词:
488- // 1) 优先读取同目录同名 .lrc 文件(如 song.mp3 → song.lrc)
489- // 2) 如果不存在,使用 tag 中的内嵌歌词(USLT / Vorbis LYRICS)
489+ // 1. 优先读取同目录同名 .lrc 文件(如 song.mp3 → song.lrc)
490+ // 2. 如果不存在,使用 tag 中的内嵌歌词(USLT / Vorbis LYRICS)
490491//
491492// musicVfsPath 为音乐文件的 VFS 全路径;tag 可为 nil
492493func loadLyricsForMusic (ctx context.Context , musicVfsPath string , tag * MusicTag ) string {
@@ -526,34 +527,26 @@ func loadLyricsForMusic(ctx context.Context, musicVfsPath string, tag *MusicTag)
526527// 优先使用 RangeReader 直接读取(本地存储无需 HTTP),失败时回退到 HTTP URL
527528// 返回 nil 表示无法获取(不影响主流程)
528529func FetchFileReader (ctx context.Context , vfsPath string ) io.ReadCloser {
529- link , _ , err := fs .Link (ctx , vfsPath , model.LinkArgs {})
530+ link , file , err := fs .Link (ctx , vfsPath , model.LinkArgs {})
530531 if err != nil || link == nil {
531532 return nil
532533 }
533- // 优先使用 RangeReader(本地存储直接读取,无需 HTTP 请求)
534- if link .RangeReader != nil {
535- rc , err := link .RangeReader .RangeRead (ctx , http_range.Range {Start : 0 , Length : - 1 })
536- if err == nil && rc != nil {
537- return rc
538- }
539- }
540- // 回退:通过 HTTP URL 读取(远程存储)
541- if link .URL == "" {
542- return nil
534+ size := link .ContentLength
535+ if size <= 0 {
536+ size = file .GetSize ()
543537 }
544- req , err := http . NewRequestWithContext ( ctx , http . MethodGet , link . URL , nil )
538+ rr , err := stream . GetRangeReaderFromLink ( size , link )
545539 if err != nil {
540+ _ = link .Close ()
546541 return nil
547542 }
548- resp , err := http . DefaultClient . Do ( req )
543+ rc , err := rr . RangeRead ( ctx , http_range. Range { Length : size } )
549544 if err != nil {
545+ _ = link .Close ()
550546 return nil
551547 }
552- if resp .StatusCode != http .StatusOK && resp .StatusCode != http .StatusPartialContent {
553- _ = resp .Body .Close ()
554- return nil
555- }
556- return resp .Body
548+ link .SyncClosers .Add (rc )
549+ return utils.ReadCloser {Reader : rc , Closer : link }
557550}
558551
559552// walkVFS 递归遍历 VFS 路径,收集匹配的媒体文件路径(每个目录都刷新缓存)
@@ -591,11 +584,11 @@ func buildMediaItemFromVFS(ctx context.Context, vfsPath string, sp *model.MediaS
591584 ext := strings .ToLower (stdpath .Ext (name ))
592585
593586 item := & model.MediaItem {
594- MediaType : sp .MediaType ,
595- ScanPathID : sp .ID ,
596- FileName : name , // 文件夹名 或 文件名
597- FolderPath : stdpath .Dir (vfsPath ), // 真实父目录
598- IsFolder : obj .IsDir (),
587+ MediaType : sp .MediaType ,
588+ ScanPathID : sp .ID ,
589+ FileName : name , // 文件夹名 或 文件名
590+ FolderPath : stdpath .Dir (vfsPath ), // 真实父目录
591+ IsFolder : obj .IsDir (),
599592 ScrapedName : strings .TrimSuffix (name , stdpath .Ext (name )), // 去掉扩展名作为默认名称
600593 }
601594
@@ -740,4 +733,4 @@ func GetSupportedExts(mediaType model.MediaType) []string {
740733 exts = append (exts , ext )
741734 }
742735 return exts
743- }
736+ }
0 commit comments