11/**
2- * 代理播放地址处理工具
2+ * 代理播放地址处理工具 - 优化版本
3+ * 解决内存泄漏问题,提升性能
34 */
45import { base64Encode } from "@/api/utils/index.js" ;
56
7+ // 缓存配置
8+ const CACHE_CONFIG = {
9+ MAX_SIZE : 100 , // 最大缓存条目数
10+ CLEANUP_INTERVAL : 300000 , // 5分钟清理一次
11+ MAX_AGE : 600000 // 缓存最大存活时间10分钟
12+ }
13+
14+ // 全局缓存对象
15+ const cache = {
16+ urlCache : new Map ( ) , // URL编码缓存
17+ headerCache : new Map ( ) , // Headers编码缓存
18+ proxyCache : new Map ( ) , // 代理URL缓存
19+ lastCleanup : Date . now ( ) // 上次清理时间
20+ }
21+
22+ // 默认User-Agent(避免重复创建)
23+ const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
24+
25+ /**
26+ * 自动清理缓存
27+ */
28+ function autoCleanupCache ( ) {
29+ const now = Date . now ( )
30+
31+ // 检查是否需要清理
32+ if ( now - cache . lastCleanup < CACHE_CONFIG . CLEANUP_INTERVAL ) {
33+ return
34+ }
35+
36+ const caches = [ cache . urlCache , cache . headerCache , cache . proxyCache ]
37+
38+ caches . forEach ( cacheMap => {
39+ // 如果缓存超过最大大小,清理最旧的条目
40+ if ( cacheMap . size > CACHE_CONFIG . MAX_SIZE ) {
41+ const entries = Array . from ( cacheMap . entries ( ) )
42+ const toDelete = entries . slice ( 0 , Math . floor ( CACHE_CONFIG . MAX_SIZE * 0.3 ) )
43+ toDelete . forEach ( ( [ key ] ) => cacheMap . delete ( key ) )
44+ }
45+
46+ // 清理过期条目
47+ for ( const [ key , value ] of cacheMap . entries ( ) ) {
48+ if ( value . timestamp && now - value . timestamp > CACHE_CONFIG . MAX_AGE ) {
49+ cacheMap . delete ( key )
50+ }
51+ }
52+ } )
53+
54+ cache . lastCleanup = now
55+
56+ // 在开发环境下输出清理信息
57+ if ( process . env . NODE_ENV === 'development' ) {
58+ console . log ( '🧹 [代理缓存] 自动清理完成' )
59+ }
60+ }
61+
62+ /**
63+ * 获取缓存的编码结果
64+ */
65+ function getCachedEncoding ( text , cacheMap ) {
66+ autoCleanupCache ( )
67+
68+ const cached = cacheMap . get ( text )
69+ if ( cached ) {
70+ return cached . value
71+ }
72+
73+ const encoded = base64Encode ( text )
74+ cacheMap . set ( text , {
75+ value : encoded ,
76+ timestamp : Date . now ( )
77+ } )
78+
79+ return encoded
80+ }
81+
682/**
783 * 获取当前选中的代理播放地址
884 * @returns {string|null } 返回代理播放地址,如果未启用代理播放则返回null
@@ -27,49 +103,74 @@ export function getCurrentProxyPlayAddress() {
27103}
28104
29105/**
30- * 构建代理播放URL
106+ * 构建代理播放URL - 优化版本
31107 * @param {string } originalUrl 原始视频地址
32108 * @param {string } proxyAddress 代理播放地址模板
33109 * @param {Object } headers 请求头对象
34110 * @returns {string } 构建后的代理播放URL
35111 */
36112export function buildProxyPlayUrl ( originalUrl , proxyAddress , headers = { } ) {
37113 try {
114+ // 创建缓存键
115+ const cacheKey = `${ originalUrl } |${ proxyAddress } |${ JSON . stringify ( headers ) } `
116+
117+ // 检查缓存
118+ autoCleanupCache ( )
119+ const cached = cache . proxyCache . get ( cacheKey )
120+ if ( cached ) {
121+ // 在开发环境下输出缓存命中信息
122+ if ( process . env . NODE_ENV === 'development' ) {
123+ console . log ( '🎯 [代理缓存] 缓存命中:' , originalUrl . substring ( 0 , 50 ) + '...' )
124+ }
125+ return cached . value
126+ }
127+
38128 // 移除代理地址中的 #名称 部分
39129 const cleanProxyAddress = proxyAddress . replace ( / # .* $ / , '' )
40130
41- // 处理默认 headers:如果 headers 为空或没有有效内容,使用当前页面的 User-Agent
131+ // 处理默认 headers:如果 headers 为空或没有有效内容,使用默认 User-Agent
42132 let finalHeaders = headers
43133 if ( ! headers || Object . keys ( headers ) . length === 0 ||
44134 ( Object . keys ( headers ) . length === 1 && ! headers [ 'user-agent' ] && ! headers [ 'User-Agent' ] ) ) {
45135 finalHeaders = {
46- 'user-agent' : navigator . userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
136+ 'user-agent' : navigator . userAgent || DEFAULT_USER_AGENT
47137 }
48138 }
49139
50140 // 将headers对象转换为JSON字符串
51141 const headersJson = JSON . stringify ( finalHeaders )
52142
53- // 对 URL 和 headers 进行 URL 安全的 base64 编码
54- const encodedUrl = base64Encode ( originalUrl )
55- const encodedHeaders = base64Encode ( headersJson )
56- const encodedType = originalUrl . split ( '/' ) . slice ( - 1 ) [ 0 ] . split ( '?' ) [ 0 ]
143+ // 使用缓存的编码结果
144+ const encodedUrl = getCachedEncoding ( originalUrl , cache . urlCache )
145+ const encodedHeaders = getCachedEncoding ( headersJson , cache . headerCache )
146+
147+ // 提取文件类型(优化字符串操作)
148+ const urlParts = originalUrl . split ( '/' )
149+ const lastPart = urlParts [ urlParts . length - 1 ]
150+ const encodedType = lastPart . split ( '?' ) [ 0 ]
57151
58- // 替换模板字符串中的${url}和${headers}
59- let proxyUrl = cleanProxyAddress
152+ // 替换模板字符串中的变量
153+ const proxyUrl = cleanProxyAddress
60154 . replace ( / \$ \{ u r l \} / g, encodeURIComponent ( encodedUrl ) )
61155 . replace ( / \$ \{ h e a d e r s \} / g, encodeURIComponent ( encodedHeaders ) )
62156 . replace ( / \$ \{ t y p e \} / g, encodedType )
63157
64- console . log ( '🔄 [代理播放] 构建代理URL:' )
65- console . log ( '📺 原始地址:' , originalUrl )
66- console . log ( '📋 原始请求头:' , headers )
67- console . log ( '📋 最终请求头:' , finalHeaders )
68- console . log ( '🌐 代理模板:' , proxyAddress )
69- console . log ( '🧹 清理后模板:' , cleanProxyAddress )
70- console . log ( '🔐 编码后URL:' , encodedUrl )
71- console . log ( '🔐 编码后Headers:' , encodedHeaders )
72- console . log ( '🔗 最终代理URL:' , proxyUrl )
158+ // 缓存结果
159+ cache . proxyCache . set ( cacheKey , {
160+ value : proxyUrl ,
161+ timestamp : Date . now ( )
162+ } )
163+
164+ // 输出详细的调试日志
165+ console . log ( '🔄 [代理播放] 构建代理URL:' )
166+ console . log ( '📺 原始地址:' , originalUrl )
167+ console . log ( '📋 原始请求头:' , headers )
168+ console . log ( '📋 最终请求头:' , finalHeaders )
169+ console . log ( '🌐 代理模板:' , proxyAddress )
170+ console . log ( '🧹 清理后模板:' , cleanProxyAddress )
171+ console . log ( '🔐 编码后URL:' , encodedUrl )
172+ console . log ( '🔐 编码后Headers:' , encodedHeaders )
173+ console . log ( '🔗 最终代理URL:' , proxyUrl )
73174
74175 return proxyUrl
75176 } catch ( error ) {
@@ -90,7 +191,10 @@ export function processVideoUrl(originalUrl, headers = {}) {
90191
91192 // 如果没有启用代理播放,直接返回原始地址
92193 if ( ! proxyAddress ) {
93- console . log ( '🎬 [直接播放] 使用原始地址:' , originalUrl )
194+ // 仅在开发环境下输出日志
195+ if ( process . env . NODE_ENV === 'development' ) {
196+ console . log ( '🎬 [直接播放] 使用原始地址:' , originalUrl . substring ( 0 , 100 ) + '...' )
197+ }
94198 return originalUrl
95199 }
96200
@@ -113,4 +217,69 @@ export function isProxyPlayEnabled() {
113217 console . error ( '检查代理播放状态失败:' , error )
114218 return false
115219 }
220+ }
221+
222+ /**
223+ * 手动清理所有缓存
224+ * @returns {Object } 清理统计信息
225+ */
226+ export function clearProxyCache ( ) {
227+ const stats = {
228+ urlCache : cache . urlCache . size ,
229+ headerCache : cache . headerCache . size ,
230+ proxyCache : cache . proxyCache . size ,
231+ totalCleared : 0
232+ }
233+
234+ // 清理所有缓存
235+ cache . urlCache . clear ( )
236+ cache . headerCache . clear ( )
237+ cache . proxyCache . clear ( )
238+ cache . lastCleanup = Date . now ( )
239+
240+ stats . totalCleared = stats . urlCache + stats . headerCache + stats . proxyCache
241+
242+ // 在开发环境下输出清理信息
243+ if ( process . env . NODE_ENV === 'development' ) {
244+ console . log ( '🧹 [代理缓存] 手动清理完成:' , stats )
245+ }
246+
247+ return stats
248+ }
249+
250+ /**
251+ * 获取缓存统计信息
252+ * @returns {Object } 缓存统计信息
253+ */
254+ export function getCacheStats ( ) {
255+ return {
256+ urlCache : cache . urlCache . size ,
257+ headerCache : cache . headerCache . size ,
258+ proxyCache : cache . proxyCache . size ,
259+ lastCleanup : new Date ( cache . lastCleanup ) . toLocaleString ( ) ,
260+ maxSize : CACHE_CONFIG . MAX_SIZE ,
261+ maxAge : CACHE_CONFIG . MAX_AGE / 1000 + 's' ,
262+ cleanupInterval : CACHE_CONFIG . CLEANUP_INTERVAL / 1000 + 's'
263+ }
264+ }
265+
266+ /**
267+ * 配置缓存参数
268+ * @param {Object } config 缓存配置
269+ */
270+ export function configureCacheSettings ( config = { } ) {
271+ if ( config . maxSize && config . maxSize > 0 ) {
272+ CACHE_CONFIG . MAX_SIZE = config . maxSize
273+ }
274+ if ( config . maxAge && config . maxAge > 0 ) {
275+ CACHE_CONFIG . MAX_AGE = config . maxAge
276+ }
277+ if ( config . cleanupInterval && config . cleanupInterval > 0 ) {
278+ CACHE_CONFIG . CLEANUP_INTERVAL = config . cleanupInterval
279+ }
280+
281+ // 在开发环境下输出配置信息
282+ if ( process . env . NODE_ENV === 'development' ) {
283+ console . log ( '⚙️ [代理缓存] 配置已更新:' , CACHE_CONFIG )
284+ }
116285}
0 commit comments