Skip to content

Commit b2c0957

Browse files
committed
feat: 添加 FNTV 媒体服务器处理器支持
1 parent 805d99e commit b2c0957

2 files changed

Lines changed: 156 additions & 0 deletions

File tree

internal/handler/fntv.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package handler
2+
3+
import (
4+
"MediaWarp/constants"
5+
"MediaWarp/internal/logging"
6+
"MediaWarp/utils"
7+
"bytes"
8+
"fmt"
9+
"io"
10+
"net/http"
11+
"net/http/httputil"
12+
"net/url"
13+
"regexp"
14+
"strconv"
15+
"time"
16+
17+
"github.com/tidwall/gjson"
18+
)
19+
20+
type FNTVHandler struct {
21+
routerRules []RegexpRouteRule // 正则路由规则
22+
proxy *httputil.ReverseProxy // 反向代理
23+
httpStrmHandler StrmHandlerFunc
24+
}
25+
26+
func NewFNTVHandler(addr string) (*FNTVHandler, error) {
27+
hanler := FNTVHandler{}
28+
target, err := url.Parse(addr)
29+
if err != nil {
30+
return nil, err
31+
}
32+
hanler.proxy = httputil.NewSingleHostReverseProxy(target)
33+
34+
hanler.routerRules = []RegexpRouteRule{
35+
{
36+
Regexp: constants.FNTVRegexp.StreamHandler,
37+
Handler: responseModifyCreater(
38+
&httputil.ReverseProxy{Director: hanler.proxy.Director},
39+
hanler.ModifyStream,
40+
),
41+
},
42+
}
43+
44+
hanler.httpStrmHandler, err = getHTTPStrmHandler()
45+
if err != nil {
46+
return nil, fmt.Errorf("创建 HTTPStrm 处理器失败: %w", err)
47+
}
48+
49+
return &hanler, nil
50+
}
51+
52+
// 转发请求至上游服务器
53+
func (hanler *FNTVHandler) ReverseProxy(writer http.ResponseWriter, request *http.Request) {
54+
hanler.proxy.ServeHTTP(writer, request)
55+
}
56+
57+
// 获取正则路由表
58+
func (hanler *FNTVHandler) GetRegexpRouteRules() []RegexpRouteRule {
59+
return hanler.routerRules
60+
}
61+
62+
// 获取图片缓存正则表达式
63+
func (hanler *FNTVHandler) GetImageCacheRegexp() *regexp.Regexp {
64+
return constants.FNTVRegexp.Cache.Image
65+
}
66+
67+
// 获取字幕缓存正则表达式
68+
func (hanler *FNTVHandler) GetSubtitleCacheRegexp() *regexp.Regexp {
69+
return constants.FNTVRegexp.Cache.Subtitle
70+
}
71+
72+
func (hanler *FNTVHandler) ModifyStream(rw *http.Response) error {
73+
startTime := time.Now()
74+
defer func() {
75+
logging.Debugf("FNTV ModifyStream 处理耗时: %s", time.Since(startTime).String())
76+
}()
77+
78+
data, err := io.ReadAll(rw.Body)
79+
if err != nil {
80+
logging.Warning("读取响应体失败:", err)
81+
return err
82+
}
83+
defer rw.Body.Close()
84+
logging.Debug(string(data))
85+
86+
jsonChain := utils.NewFromBytesWithCopy(data, jsonChainOption)
87+
88+
code := jsonChain.Get("code").Int()
89+
if code != 0 {
90+
logging.Warningf("stream 响应 code: %d, msg: %s", code, jsonChain.Get("msg").String())
91+
return nil
92+
}
93+
94+
filePathRes := jsonChain.Get("data.file_stream.path")
95+
if filePathRes.Type != gjson.String {
96+
logging.Warningf("stream 响应 data.file_stream.path 字段不正确: %#v", filePathRes)
97+
return nil
98+
}
99+
100+
filePath := filePathRes.String()
101+
102+
strmFileType, opt := recgonizeStrmFileType(filePath)
103+
104+
switch strmFileType {
105+
case constants.HTTPStrm: // HTTPStrm 设置支持直链播放并且支持转码
106+
urlRes := jsonChain.Get("data.direct_link_qualities.0.url")
107+
if urlRes.Type != gjson.String {
108+
logging.Warningf("stream 响应 data.direct_link_qualities.0.url 字段不正确: %#v", urlRes)
109+
return nil
110+
}
111+
112+
redirectURL := hanler.httpStrmHandler(urlRes.String(), rw.Request.Header.Get("User-Agent"))
113+
jsonChain.Set(
114+
"data.direct_link_qualities.0.resolution",
115+
"HTTPStrm 直链",
116+
).Set(
117+
"data.direct_link_qualities.0.url",
118+
redirectURL,
119+
)
120+
121+
case constants.AlistStrm: // AlistStm 设置支持直链播放并且禁止转码
122+
remoteFilepathRes := jsonChain.Get("data.direct_link_qualities.0.url")
123+
if remoteFilepathRes.Type != gjson.String {
124+
logging.Warningf("stream 响应 data.direct_link_qualities.0.url 字段不正确: %#v", remoteFilepathRes)
125+
return nil
126+
}
127+
128+
redirectURL := alistStrmHandler(remoteFilepathRes.String(), opt.(string))
129+
jsonChain.Set(
130+
"data.direct_link_qualities.0.resolution",
131+
"AlistStrm 直链 - 原画",
132+
).Set(
133+
"data.direct_link_qualities.0.url",
134+
redirectURL,
135+
)
136+
137+
default:
138+
logging.Debugf("%s 未匹配任何 Strm 类型,保持原有播放链接不变", filePath)
139+
}
140+
141+
data, err = jsonChain.Result()
142+
if err != nil {
143+
logging.Warning("操作 FNTV Stream Json 错误:", err)
144+
return err
145+
}
146+
rw.Header.Set("Content-Type", "application/json") // 更新 Content-Type 头
147+
rw.Header.Set("Content-Length", strconv.Itoa(len(data)))
148+
rw.Body = io.NopCloser(bytes.NewReader(data))
149+
150+
return nil
151+
}
152+
153+
var _ MediaServerHandler = (*FNTVHandler)(nil)

internal/handler/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ func Init() error {
2727
mediaServerHandler, err = NewEmbyServerHandler(config.MediaServer.ADDR, config.MediaServer.AUTH)
2828
case constants.JELLYFIN:
2929
mediaServerHandler, err = NewJellyfinHandler(config.MediaServer.ADDR, config.MediaServer.AUTH)
30+
case constants.FNTV:
31+
mediaServerHandler, err = NewFNTVHandler(config.MediaServer.ADDR)
32+
3033
default:
3134
err = ErrInvalidMediaServerType
3235
}

0 commit comments

Comments
 (0)