-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy pathproxyPlayer.js
More file actions
285 lines (244 loc) · 8.47 KB
/
proxyPlayer.js
File metadata and controls
285 lines (244 loc) · 8.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/**
* 代理播放地址处理工具 - 优化版本
* 解决内存泄漏问题,提升性能
*/
import {base64Encode} from "@/api/utils/index.js";
// 缓存配置
const CACHE_CONFIG = {
MAX_SIZE: 100, // 最大缓存条目数
CLEANUP_INTERVAL: 300000, // 5分钟清理一次
MAX_AGE: 600000 // 缓存最大存活时间10分钟
}
// 全局缓存对象
const cache = {
urlCache: new Map(), // URL编码缓存
headerCache: new Map(), // Headers编码缓存
proxyCache: new Map(), // 代理URL缓存
lastCleanup: Date.now() // 上次清理时间
}
// 默认User-Agent(避免重复创建)
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
/**
* 自动清理缓存
*/
function autoCleanupCache() {
const now = Date.now()
// 检查是否需要清理
if (now - cache.lastCleanup < CACHE_CONFIG.CLEANUP_INTERVAL) {
return
}
const caches = [cache.urlCache, cache.headerCache, cache.proxyCache]
caches.forEach(cacheMap => {
// 如果缓存超过最大大小,清理最旧的条目
if (cacheMap.size > CACHE_CONFIG.MAX_SIZE) {
const entries = Array.from(cacheMap.entries())
const toDelete = entries.slice(0, Math.floor(CACHE_CONFIG.MAX_SIZE * 0.3))
toDelete.forEach(([key]) => cacheMap.delete(key))
}
// 清理过期条目
for (const [key, value] of cacheMap.entries()) {
if (value.timestamp && now - value.timestamp > CACHE_CONFIG.MAX_AGE) {
cacheMap.delete(key)
}
}
})
cache.lastCleanup = now
// 在开发环境下输出清理信息
if (process.env.NODE_ENV === 'development') {
console.log('🧹 [代理缓存] 自动清理完成')
}
}
/**
* 获取缓存的编码结果
*/
function getCachedEncoding(text, cacheMap) {
autoCleanupCache()
const cached = cacheMap.get(text)
if (cached) {
return cached.value
}
const encoded = base64Encode(text)
cacheMap.set(text, {
value: encoded,
timestamp: Date.now()
})
return encoded
}
/**
* 获取当前选中的代理播放地址
* @returns {string|null} 返回代理播放地址,如果未启用代理播放则返回null
*/
export function getCurrentProxyPlayAddress() {
try {
// 从addressSettings读取代理播放配置
const savedAddresses = JSON.parse(localStorage.getItem('addressSettings') || '{}')
const proxyPlayEnabled = savedAddresses.proxyPlayEnabled || false
const proxyPlay = savedAddresses.proxyPlay || ''
// 如果代理播放未启用或地址为空,返回null
if (!proxyPlayEnabled || !proxyPlay || proxyPlay.trim() === '') {
return null
}
return proxyPlay.trim()
} catch (error) {
console.error('获取代理播放地址失败:', error)
return null
}
}
/**
* 构建代理播放URL - 优化版本
* @param {string} originalUrl 原始视频地址
* @param {string} proxyAddress 代理播放地址模板
* @param {Object} headers 请求头对象
* @returns {string} 构建后的代理播放URL
*/
export function buildProxyPlayUrl(originalUrl, proxyAddress, headers = {}) {
try {
// 创建缓存键
const cacheKey = `${originalUrl}|${proxyAddress}|${JSON.stringify(headers)}`
// 检查缓存
autoCleanupCache()
const cached = cache.proxyCache.get(cacheKey)
if (cached) {
// 在开发环境下输出缓存命中信息
if (process.env.NODE_ENV === 'development') {
console.log('🎯 [代理缓存] 缓存命中:', originalUrl.substring(0, 50) + '...')
}
return cached.value
}
// 移除代理地址中的 #名称 部分
const cleanProxyAddress = proxyAddress.replace(/#.*$/, '')
// 处理默认 headers:如果 headers 为空或没有有效内容,使用默认 User-Agent
let finalHeaders = headers
if (!headers || Object.keys(headers).length === 0 ||
(Object.keys(headers).length === 1 && !headers['user-agent'] && !headers['User-Agent'])) {
finalHeaders = {
'user-agent': navigator.userAgent || DEFAULT_USER_AGENT
}
}
// 将headers对象转换为JSON字符串
const headersJson = JSON.stringify(finalHeaders)
// 使用缓存的编码结果
const encodedUrl = getCachedEncoding(originalUrl, cache.urlCache)
const encodedHeaders = getCachedEncoding(headersJson, cache.headerCache)
// 提取文件类型(优化字符串操作)
const urlParts = originalUrl.split('/')
const lastPart = urlParts[urlParts.length - 1]
const encodedType = lastPart.split('?')[0]
// 替换模板字符串中的变量
const proxyUrl = cleanProxyAddress
.replace(/\$\{url\}/g, encodeURIComponent(encodedUrl))
.replace(/\$\{headers\}/g, encodeURIComponent(encodedHeaders))
.replace(/\$\{type\}/g, encodedType)
// 缓存结果
cache.proxyCache.set(cacheKey, {
value: proxyUrl,
timestamp: Date.now()
})
// 输出详细的调试日志
console.log('🔄 [代理播放] 构建代理URL:')
console.log('📺 原始地址:', originalUrl)
console.log('📋 原始请求头:', headers)
console.log('📋 最终请求头:', finalHeaders)
console.log('🌐 代理模板:', proxyAddress)
console.log('🧹 清理后模板:', cleanProxyAddress)
console.log('🔐 编码后URL:', encodedUrl)
console.log('🔐 编码后Headers:', encodedHeaders)
console.log('🔗 最终代理URL:', proxyUrl)
return proxyUrl
} catch (error) {
console.error('构建代理播放URL失败:', error)
return originalUrl // 失败时返回原始地址
}
}
/**
* 处理视频地址,如果启用了代理播放则返回代理URL,否则返回原始URL
* @param {string} originalUrl 原始视频地址
* @param {Object} headers 请求头对象
* @returns {string} 处理后的视频地址
*/
export function processVideoUrl(originalUrl, headers = {}) {
// 获取当前代理播放地址
const proxyAddress = getCurrentProxyPlayAddress()
// 如果没有启用代理播放,直接返回原始地址
if (!proxyAddress) {
// 仅在开发环境下输出日志
if (process.env.NODE_ENV === 'development') {
console.log('🎬 [直接播放] 使用原始地址:', originalUrl.substring(0, 100) + '...')
}
return originalUrl
}
// 构建并返回代理播放URL
return buildProxyPlayUrl(originalUrl, proxyAddress, headers)
}
/**
* 检查是否启用了代理播放
* @returns {boolean} 是否启用代理播放
*/
export function isProxyPlayEnabled() {
try {
const savedAddresses = JSON.parse(localStorage.getItem('addressSettings') || '{}')
const proxyPlayEnabled = savedAddresses.proxyPlayEnabled || false
const proxyPlay = savedAddresses.proxyPlay || ''
return proxyPlayEnabled && proxyPlay && proxyPlay.trim() !== ''
} catch (error) {
console.error('检查代理播放状态失败:', error)
return false
}
}
/**
* 手动清理所有缓存
* @returns {Object} 清理统计信息
*/
export function clearProxyCache() {
const stats = {
urlCache: cache.urlCache.size,
headerCache: cache.headerCache.size,
proxyCache: cache.proxyCache.size,
totalCleared: 0
}
// 清理所有缓存
cache.urlCache.clear()
cache.headerCache.clear()
cache.proxyCache.clear()
cache.lastCleanup = Date.now()
stats.totalCleared = stats.urlCache + stats.headerCache + stats.proxyCache
// 在开发环境下输出清理信息
if (process.env.NODE_ENV === 'development') {
console.log('🧹 [代理缓存] 手动清理完成:', stats)
}
return stats
}
/**
* 获取缓存统计信息
* @returns {Object} 缓存统计信息
*/
export function getCacheStats() {
return {
urlCache: cache.urlCache.size,
headerCache: cache.headerCache.size,
proxyCache: cache.proxyCache.size,
lastCleanup: new Date(cache.lastCleanup).toLocaleString(),
maxSize: CACHE_CONFIG.MAX_SIZE,
maxAge: CACHE_CONFIG.MAX_AGE / 1000 + 's',
cleanupInterval: CACHE_CONFIG.CLEANUP_INTERVAL / 1000 + 's'
}
}
/**
* 配置缓存参数
* @param {Object} config 缓存配置
*/
export function configureCacheSettings(config = {}) {
if (config.maxSize && config.maxSize > 0) {
CACHE_CONFIG.MAX_SIZE = config.maxSize
}
if (config.maxAge && config.maxAge > 0) {
CACHE_CONFIG.MAX_AGE = config.maxAge
}
if (config.cleanupInterval && config.cleanupInterval > 0) {
CACHE_CONFIG.CLEANUP_INTERVAL = config.cleanupInterval
}
// 在开发环境下输出配置信息
if (process.env.NODE_ENV === 'development') {
console.log('⚙️ [代理缓存] 配置已更新:', CACHE_CONFIG)
}
}