Skip to content

Commit 455398f

Browse files
author
Taois
committed
feat: 优化代理性能,修复列表重复key错误
1 parent 0b6799d commit 455398f

File tree

2 files changed

+191
-22
lines changed

2 files changed

+191
-22
lines changed

dashboard/src/components/VideoGrid.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
>
99
<a-grid :cols="{ xs: 2, sm: 3, md: 4, lg: 5, xl: 6, xxl: 8 }" :rowGap="16" :colGap="12">
1010
<a-grid-item
11-
v-for="video in videos"
12-
:key="video.vod_id"
11+
v-for="(video, index) in videos"
12+
:key="`${video.vod_id}_${index}_${video.vod_name || ''}`"
1313
class="video_list_hover"
1414
>
1515
<div class="video_list_item" @click="handleVideoClick(video)">

dashboard/src/utils/proxyPlayer.js

Lines changed: 189 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,84 @@
11
/**
2-
* 代理播放地址处理工具
2+
* 代理播放地址处理工具 - 优化版本
3+
* 解决内存泄漏问题,提升性能
34
*/
45
import {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
*/
36112
export 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(/\$\{url\}/g, encodeURIComponent(encodedUrl))
61155
.replace(/\$\{headers\}/g, encodeURIComponent(encodedHeaders))
62156
.replace(/\$\{type\}/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

Comments
 (0)