Skip to content

Commit ab4c353

Browse files
authored
Merge pull request #119 from QiaoKes/develop
1. [fix] 修复部分网盘STRM播放失败的问题
2 parents 1aedb1c + 6b83666 commit ab4c353

3 files changed

Lines changed: 147 additions & 165 deletions

File tree

README.md

Lines changed: 77 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
- **原生桌面体验** - 基于飞牛影视Web端构建的桌面应用,提供类原生体验
1616
- **多账户管理** - 支持自动登录,支持多账户管理,自由切换账户和服务器
17-
- **硬解播放** - 支持H264 / HEVC / VP9 / AV1,具体支持查看下面感谢项目
18-
- **直链播放** - 适配官方直链播放,默认使用直链,可以在托盘处调整为nas代理模式
19-
- **进度回传** - mpv播放器支持实时将进度回传到飞牛服务器
17+
- **硬解播放** - 使用MPV播放器,支持H264 / HEVC / VP9 / AV1等编码格式
18+
- **直链播放** - 适配官方直链 / STRM播放,默认使用302重定向,可以在托盘处调整为nas代理模式
19+
- **进度回传** - MPV播放器支持实时将进度回传到飞牛服务器
2020
- **弹幕支持** - MPV播放器支持弹幕自动匹配加载,无法匹配时支持手动搜索
2121
- **视频增强** - 内置anime4K着色器以及对应预设模式
2222
- **智能跳过** - 可在MPV播放器界面设置。支持三种跳过片头片尾模式:章节检查,手动设置片头片尾,快捷键跳过固定时长
@@ -34,72 +34,72 @@
3434

3535
感谢这些来自爱发电的赞助者:
3636

37-
<!-- AFDIAN-ACTION:START -->
38-
39-
<a href="https://afdian.com/u/bf093216d1da11f085b852540025c377">
40-
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-blue.png?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_7kDX" title="爱发电用户_7kDX"/>
41-
</a>
42-
<a href="https://afdian.com/u/5251e4e2d1c611f0b83d52540025c377">
43-
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_5251e" title="爱发电用户_5251e"/>
44-
</a>
45-
<a href="https://afdian.com/u/ec6015fcd0ca11ef8f8e52540025c377">
46-
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_ec601" title="爱发电用户_ec601"/>
47-
</a>
48-
<a href="https://afdian.com/u/713bc866afc811f093a952540025c377">
49-
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_7WxX" title="爱发电用户_7WxX"/>
50-
</a>
51-
<a href="https://afdian.com/u/f9548ae809f311ef805e52540025c377">
52-
<img src="https://pic1.afdiancdn.com/user/f9548ae809f311ef805e52540025c377/avatar/b585c02959db06c4ea614f6e94fba294_w279_h252_s65.jpg.gif?imageView2/1/w/120/h/120" width="40" height="40" alt="1" title="1"/>
53-
</a>
54-
<a href="https://afdian.com/u/4514cc8c9a8411f0992b52540025c377">
55-
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_4514c" title="爱发电用户_4514c"/>
56-
</a>
57-
<a href="https://afdian.com/u/2685303096b611f0b4a652540025c377">
58-
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/?imageView2/1/w/120/h/120" width="40" height="40" alt="嬴游仙人莫迪" title="嬴游仙人莫迪"/>
59-
</a>
60-
<a href="https://afdian.com/u/8a03268e8ba411f0bcbb52540025c377">
61-
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-orange.png?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_e6g3" title="爱发电用户_e6g3"/>
62-
</a>
63-
64-
<details>
65-
<summary>点我 打开/关闭 赞助者列表</summary>
66-
67-
<a href="https://afdian.com/u/bf093216d1da11f085b852540025c377">
68-
爱发电用户_7kDX
69-
</a>
70-
<span>( 1 次赞助, 共 ¥10 ) 留言: </span><br>
71-
<a href="https://afdian.com/u/5251e4e2d1c611f0b83d52540025c377">
72-
爱发电用户_5251e
73-
</a>
74-
<span>( 1 次赞助, 共 ¥20 ) 留言: </span><br>
75-
<a href="https://afdian.com/u/ec6015fcd0ca11ef8f8e52540025c377">
76-
爱发电用户_ec601
77-
</a>
78-
<span>( 1 次赞助, 共 ¥10 ) 留言: 不错不错</span><br>
79-
<a href="https://afdian.com/u/713bc866afc811f093a952540025c377">
80-
爱发电用户_7WxX
81-
</a>
82-
<span>( 1 次赞助, 共 ¥10 ) 留言: 加油,支持一杯蜜雪</span><br>
83-
<a href="https://afdian.com/u/f9548ae809f311ef805e52540025c377">
84-
1
85-
</a>
86-
<span>( 1 次赞助, 共 ¥10 ) 留言: fntv</span><br>
87-
<a href="https://afdian.com/u/4514cc8c9a8411f0992b52540025c377">
88-
爱发电用户_4514c
89-
</a>
90-
<span>( 1 次赞助, 共 ¥10 ) 留言: </span><br>
91-
<a href="https://afdian.com/u/2685303096b611f0b4a652540025c377">
92-
嬴游仙人莫迪
93-
</a>
94-
<span>( 1 次赞助, 共 ¥60 ) 留言: 谢谢,我是真的很喜欢...</span><br>
95-
<a href="https://afdian.com/u/8a03268e8ba411f0bcbb52540025c377">
96-
爱发电用户_e6g3
97-
</a>
98-
<span>( 1 次赞助, 共 ¥20 ) 留言: 给几个建议我是mac...</span><br>
99-
100-
</details>
101-
<!-- 注意: 尽量将标签前靠,否则经测试可能被 GitHub 解析为代码块 -->
102-
37+
<!-- AFDIAN-ACTION:START -->
38+
39+
<a href="https://afdian.com/u/bf093216d1da11f085b852540025c377">
40+
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-blue.png?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_7kDX" title="爱发电用户_7kDX"/>
41+
</a>
42+
<a href="https://afdian.com/u/5251e4e2d1c611f0b83d52540025c377">
43+
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_5251e" title="爱发电用户_5251e"/>
44+
</a>
45+
<a href="https://afdian.com/u/ec6015fcd0ca11ef8f8e52540025c377">
46+
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_ec601" title="爱发电用户_ec601"/>
47+
</a>
48+
<a href="https://afdian.com/u/713bc866afc811f093a952540025c377">
49+
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_7WxX" title="爱发电用户_7WxX"/>
50+
</a>
51+
<a href="https://afdian.com/u/f9548ae809f311ef805e52540025c377">
52+
<img src="https://pic1.afdiancdn.com/user/f9548ae809f311ef805e52540025c377/avatar/b585c02959db06c4ea614f6e94fba294_w279_h252_s65.jpg.gif?imageView2/1/w/120/h/120" width="40" height="40" alt="1" title="1"/>
53+
</a>
54+
<a href="https://afdian.com/u/4514cc8c9a8411f0992b52540025c377">
55+
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_4514c" title="爱发电用户_4514c"/>
56+
</a>
57+
<a href="https://afdian.com/u/2685303096b611f0b4a652540025c377">
58+
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png?imageView2/1/?imageView2/1/w/120/h/120" width="40" height="40" alt="嬴游仙人莫迪" title="嬴游仙人莫迪"/>
59+
</a>
60+
<a href="https://afdian.com/u/8a03268e8ba411f0bcbb52540025c377">
61+
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-orange.png?imageView2/1/w/120/h/120" width="40" height="40" alt="爱发电用户_e6g3" title="爱发电用户_e6g3"/>
62+
</a>
63+
64+
<details>
65+
<summary>点我 打开/关闭 赞助者列表</summary>
66+
67+
<a href="https://afdian.com/u/bf093216d1da11f085b852540025c377">
68+
爱发电用户_7kDX
69+
</a>
70+
<span>( 1 次赞助, 共 ¥10 ) 留言: </span><br>
71+
<a href="https://afdian.com/u/5251e4e2d1c611f0b83d52540025c377">
72+
爱发电用户_5251e
73+
</a>
74+
<span>( 1 次赞助, 共 ¥20 ) 留言: </span><br>
75+
<a href="https://afdian.com/u/ec6015fcd0ca11ef8f8e52540025c377">
76+
爱发电用户_ec601
77+
</a>
78+
<span>( 1 次赞助, 共 ¥10 ) 留言: 不错不错</span><br>
79+
<a href="https://afdian.com/u/713bc866afc811f093a952540025c377">
80+
爱发电用户_7WxX
81+
</a>
82+
<span>( 1 次赞助, 共 ¥10 ) 留言: 加油,支持一杯蜜雪</span><br>
83+
<a href="https://afdian.com/u/f9548ae809f311ef805e52540025c377">
84+
1
85+
</a>
86+
<span>( 1 次赞助, 共 ¥10 ) 留言: fntv</span><br>
87+
<a href="https://afdian.com/u/4514cc8c9a8411f0992b52540025c377">
88+
爱发电用户_4514c
89+
</a>
90+
<span>( 1 次赞助, 共 ¥10 ) 留言: </span><br>
91+
<a href="https://afdian.com/u/2685303096b611f0b4a652540025c377">
92+
嬴游仙人莫迪
93+
</a>
94+
<span>( 1 次赞助, 共 ¥60 ) 留言: 谢谢,我是真的很喜欢...</span><br>
95+
<a href="https://afdian.com/u/8a03268e8ba411f0bcbb52540025c377">
96+
爱发电用户_e6g3
97+
</a>
98+
<span>( 1 次赞助, 共 ¥20 ) 留言: 给几个建议我是mac...</span><br>
99+
100+
</details>
101+
<!-- 注意: 尽量将标签前靠,否则经测试可能被 GitHub 解析为代码块 -->
102+
103103
<!-- AFDIAN-ACTION:END -->
104104

105105
## 📦 安装方法
@@ -161,11 +161,7 @@ npm run build:linux
161161

162162
## 常用问题Q&A
163163

164-
### 1. 直接播放无法客户端硬解,还是在服务端解码?
165-
166-
只有mpv播放能保证直链硬解,其余的虽然浏览器支持了硬解,但是飞牛网页端识别有问题,还是会走服务端转码,需要飞牛修复。
167-
168-
### 2. mpv播放器功能有点少,怎么客制化,想添加补帧滤镜等?
164+
### 1. mpv播放器功能有点少,怎么客制化,想添加补帧滤镜等?
169165

170166
1. 自动方法
171167
克隆fntv-mpv仓库,自己改一下相关配置:[fntv-mpv-config](https://github.com/QiaoKes/fntv-mpv-config)
@@ -174,35 +170,27 @@ npm run build:linux
174170

175171
注意重新安装或者更新,会清空安装目录,注意备份你的mpv插件目录。
176172

177-
### 3. 是否支持网盘挂载播放?
178-
179-
支持,飞牛官方挂载的不支持302,需要官方支持。alist没有测试过,可以试一试。
173+
### 2. 能否支持potplayer?
180174

181-
### 4. 能否支持potplayer?
175+
目前我这边没有使用potplayer的需求,如果需要的话可以自行修改源码适配一下,已留好interface,只需要适配。
182176

183-
目前我这边没有使用potplayer的需求,如果需要的话可以自行修改源码适配一下。
184-
185-
### 5. 是否支持飞牛connect登录?
177+
### 3. 是否支持飞牛connect登录?
186178

187179
官方未开放相关API,无法支持。
188180

189-
### 6. 域名账号密码正确但是无法登录?
190-
191-
只支持正常dns解析的域名,和IP,其余的不支持。
192-
193-
### 7. 弹幕相关问题?
181+
### 4. 弹幕相关问题?
194182

195183
弹幕问题查看uosc_danmaku的文档,根据文档内容调整配置。
196184

197-
### 8.登录完客户端后,如果服务器连接不上登录会超时卡透明屏,无法切换或修改服务器配置,卸载重装也不行
185+
### 5. 登录完客户端后,如果服务器连接不上登录会超时卡透明屏,无法切换或修改服务器配置,卸载重装也不行
198186

199187
去C:\\Users\\{你的计算机用户名}\\.fntv 下面把config.json删除了,因为连接成功后实际上加载的还是飞牛网页端,没响应当然会透明了。
200188

201-
### 9.打开弹幕视频掉帧
189+
### 6. 打开弹幕视频掉帧
202190

203191
打开弹幕时,默认开启fps平滑滤镜,比较吃性能,不需要可以去安装目录下的third_party\fntv-mpv\portable_config\script-opts下uosc_danmaku.conf关闭相关配置
204192

205-
### 10.双显卡,调用时发现使用核显
193+
### 7. 视频播放卡慢,双显卡,调用时发现使用核显
206194

207195
以下两种方法任选其一:
208196

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fntv",
3-
"version": "2.5.2",
3+
"version": "2.5.3",
44
"description": "A fntv app built with Electron",
55
"main": "dest/main/main.js",
66
"scripts": {
Lines changed: 69 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
package utils
22

33
import (
4-
"bytes"
54
"crypto/sha1"
65
"crypto/tls"
76
"encoding/hex"
87
"encoding/json"
98
"io"
109
"net/http"
11-
"net/http/httputil"
12-
"net/url"
1310
"time"
1411

1512
"proxy/pkg/logger"
@@ -74,94 +71,91 @@ func PassthroughHeaders(req *http.Request) map[string]string {
7471
return headers
7572
}
7673

77-
// DynamicProxy 执行透明代理
74+
// DynamicProxy 实现流式管道代理,支持自动跟随重定向
7875
func DynamicProxy(c *gin.Context, targetURL string, extraHeaders map[string]string, skipVerify bool) {
79-
// 使用recover来捕获可能的panic
80-
defer func() {
81-
if err := recover(); err != nil {
82-
// 检查是否是http.ErrAbortHandler错误
83-
if err == http.ErrAbortHandler {
84-
// logger.Debugf("客户端断开连接,忽略错误: %v", err)
85-
return
86-
}
87-
// 其他panic重新抛出
88-
panic(err)
89-
}
90-
}()
91-
92-
// 解析目标URL
93-
target, err := url.Parse(targetURL)
76+
// 1. 创建 HTTP 请求
77+
// 注意:使用 c.Request.Context(),这样客户端断开连接时,下载也会自动停止
78+
req, err := http.NewRequestWithContext(c.Request.Context(), c.Request.Method, targetURL, c.Request.Body)
9479
if err != nil {
95-
c.JSON(500, gin.H{"error": "Invalid target URL"})
80+
c.JSON(500, gin.H{"error": "Failed to create request"})
9681
return
9782
}
9883

99-
// 创建反向代理
100-
proxy := httputil.NewSingleHostReverseProxy(target)
101-
102-
// 设置超时时间
103-
proxy.Transport = &http.Transport{
104-
ResponseHeaderTimeout: 30 * time.Second,
105-
TLSClientConfig: &tls.Config{
106-
InsecureSkipVerify: skipVerify,
107-
},
84+
// 2. 复制客户端的 Header 到新请求
85+
// 我们需要小心过滤掉一些 Hop-by-hop 的 Header
86+
skipHeaders := map[string]bool{
87+
"Host": true, // Host 由 http.Client 根据 URL 自动设置
88+
"Content-Length": true, // 由 req.Body 自动处理
89+
"Transfer-Encoding": true,
90+
"Connection": true,
91+
"Keep-Alive": true,
92+
"Proxy-Authenticate": true,
93+
"Proxy-Authorization": true,
94+
"Te": true,
95+
"Trailers": true,
96+
"Upgrade": true,
10897
}
10998

110-
// 修改请求前的处理
111-
proxy.Director = func(req *http.Request) {
112-
// 设置原始请求信息
113-
req.URL.Scheme = target.Scheme
114-
req.URL.Host = target.Host
115-
req.URL.Path = target.Path
116-
req.URL.RawQuery = target.RawQuery
117-
req.Host = target.Host
118-
119-
// 复制原始请求的头部
120-
for key, values := range c.Request.Header {
121-
for _, value := range values {
122-
req.Header.Set(key, value)
99+
for k, v := range c.Request.Header {
100+
if !skipHeaders[k] {
101+
for _, vv := range v {
102+
req.Header.Add(k, vv)
123103
}
124104
}
105+
}
125106

126-
// 添加额外的头部信息
127-
for key, value := range extraHeaders {
128-
req.Header.Set(key, value)
129-
}
130-
131-
logger.Infof("method:%s path:%s query:%s, header:%v", req.Method, req.URL.Path, req.URL.RawQuery, req.Header)
107+
// 添加额外的 Header
108+
for k, v := range extraHeaders {
109+
req.Header.Set(k, v)
110+
}
132111

133-
// 设置请求方法
134-
req.Method = c.Request.Method
112+
// 3. 配置 HTTP Client
113+
client := &http.Client{
114+
// 自动跟随重定向是 http.Client 的默认行为,无需额外配置
115+
// 只要不设置 CheckRedirect,它就会自动处理 302 直到拿到 200
116+
Timeout: 0, // 设置为 0,因为下载大文件或视频流需要长时间保持连接
117+
Transport: &http.Transport{
118+
TLSClientConfig: &tls.Config{InsecureSkipVerify: skipVerify},
119+
MaxIdleConns: 100,
120+
IdleConnTimeout: 90 * time.Second,
121+
DisableCompression: true, // 对于视频流,通常不需要压缩,且压缩可能导致流式传输问题
122+
},
123+
}
135124

136-
// 如果有请求体,复制它
137-
if c.Request.Body != nil {
138-
bodyBytes, err := io.ReadAll(c.Request.Body)
139-
if err == nil {
140-
req.Body = io.NopCloser(bytes.NewReader(bodyBytes))
141-
req.ContentLength = int64(len(bodyBytes))
125+
// 4. 发起请求 (这一步会自动处理 302 跳转)
126+
resp, err := client.Do(req)
127+
if err != nil {
128+
logger.Errorf("代理请求失败: %v", err)
129+
// 如果客户端已经断开,就不返回错误了
130+
if c.Request.Context().Err() == nil {
131+
c.Status(http.StatusBadGateway)
132+
}
133+
return
134+
}
135+
defer resp.Body.Close()
136+
137+
// 5. 将目标服务器的响应 Header 复制回给客户端
138+
for k, v := range resp.Header {
139+
// 同样过滤掉一些 Header
140+
if !skipHeaders[k] {
141+
for _, vv := range v {
142+
c.Writer.Header().Add(k, vv)
142143
}
143144
}
144145
}
145146

146-
// 修改响应后的处理
147-
proxy.ModifyResponse = func(resp *http.Response) error {
148-
// 打印相应头
149-
logger.Infof("响应状态: %s, 头部: %v", resp.Status, resp.Header)
150-
// 可以在这里修改响应头部或内容
151-
return nil
152-
}
147+
// 设置状态码
148+
c.Status(resp.StatusCode)
153149

154-
// 处理错误 - 修复:避免重复写入响应头
155-
proxy.ErrorHandler = func(w http.ResponseWriter, req *http.Request, err error) {
156-
// 检查响应是否已经开始写入
157-
if c.Writer.Written() {
158-
logger.Debugf("代理错误,但响应已开始写入: %v", err)
159-
return
160-
}
161-
logger.Debugf("代理错误: %v", err)
162-
c.JSON(500, gin.H{"error": "Proxy error", "details": err.Error()})
163-
}
150+
// 6. 关键步骤:建立数据管道
151+
// 直接将上游的 Body 流式拷贝到 ResponseWriter
152+
// 这样数据来多少发多少,不会占用服务器内存
153+
buf := make([]byte, 32*1024) // 32KB 缓冲区
154+
_, err = io.CopyBuffer(c.Writer, resp.Body, buf)
164155

165-
// 执行代理
166-
proxy.ServeHTTP(c.Writer, c.Request)
156+
if err != nil {
157+
// 这里的错误通常是因为客户端(播放器)关闭了连接,或者是网络中断
158+
// 不需要 panic,只需要记录日志即可
159+
logger.Debugf("流式传输中断 (可能是客户端主动断开): %v", err)
160+
}
167161
}

0 commit comments

Comments
 (0)