进度条图标自定义
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
@@ -6268,6 +6268,9 @@ const ThemeConfigComponent = ({
|
|||||||
customCSS: '',
|
customCSS: '',
|
||||||
enableCache: true,
|
enableCache: true,
|
||||||
cacheMinutes: 1440, // 默认1天(1440分钟)
|
cacheMinutes: 1440, // 默认1天(1440分钟)
|
||||||
|
progressThumbType: 'default' as 'default' | 'preset' | 'custom',
|
||||||
|
progressThumbPresetId: '',
|
||||||
|
progressThumbCustomUrl: '',
|
||||||
});
|
});
|
||||||
const [loginBackgroundImages, setLoginBackgroundImages] = useState<string[]>(['']);
|
const [loginBackgroundImages, setLoginBackgroundImages] = useState<string[]>(['']);
|
||||||
const [registerBackgroundImages, setRegisterBackgroundImages] = useState<string[]>(['']);
|
const [registerBackgroundImages, setRegisterBackgroundImages] = useState<string[]>(['']);
|
||||||
@@ -6280,6 +6283,9 @@ const ThemeConfigComponent = ({
|
|||||||
customCSS: config.ThemeConfig.customCSS || '',
|
customCSS: config.ThemeConfig.customCSS || '',
|
||||||
enableCache: config.ThemeConfig.enableCache !== false,
|
enableCache: config.ThemeConfig.enableCache !== false,
|
||||||
cacheMinutes: config.ThemeConfig.cacheMinutes || 1440,
|
cacheMinutes: config.ThemeConfig.cacheMinutes || 1440,
|
||||||
|
progressThumbType: config.ThemeConfig.progressThumbType || 'default',
|
||||||
|
progressThumbPresetId: config.ThemeConfig.progressThumbPresetId || '',
|
||||||
|
progressThumbCustomUrl: config.ThemeConfig.progressThumbCustomUrl || '',
|
||||||
});
|
});
|
||||||
|
|
||||||
// 解析背景图配置
|
// 解析背景图配置
|
||||||
@@ -6711,6 +6717,170 @@ const ThemeConfigComponent = ({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 进度条图标配置 */}
|
||||||
|
<div className='bg-white dark:bg-gray-800 rounded-lg p-6 border border-gray-200 dark:border-gray-700'>
|
||||||
|
<h3 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2'>
|
||||||
|
<Palette className='w-5 h-5' />
|
||||||
|
进度条图标
|
||||||
|
</h3>
|
||||||
|
<p className='text-sm text-gray-600 dark:text-gray-400 mb-4'>
|
||||||
|
自定义视频播放器进度条的滑块图标,让播放器更具个性
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* 图标类型选择 */}
|
||||||
|
<div className='space-y-4 mb-6'>
|
||||||
|
<label className='flex items-center space-x-3 cursor-pointer'>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
checked={themeSettings.progressThumbType === 'default'}
|
||||||
|
onChange={() =>
|
||||||
|
setThemeSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
progressThumbType: 'default',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className='w-4 h-4 text-blue-600'
|
||||||
|
/>
|
||||||
|
<span className='text-gray-900 dark:text-gray-100'>
|
||||||
|
默认圆点
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label className='flex items-center space-x-3 cursor-pointer'>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
checked={themeSettings.progressThumbType === 'preset'}
|
||||||
|
onChange={() =>
|
||||||
|
setThemeSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
progressThumbType: 'preset',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className='w-4 h-4 text-blue-600'
|
||||||
|
/>
|
||||||
|
<span className='text-gray-900 dark:text-gray-100'>
|
||||||
|
内置图标
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label className='flex items-center space-x-3 cursor-pointer'>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
checked={themeSettings.progressThumbType === 'custom'}
|
||||||
|
onChange={() =>
|
||||||
|
setThemeSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
progressThumbType: 'custom',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className='w-4 h-4 text-blue-600'
|
||||||
|
/>
|
||||||
|
<span className='text-gray-900 dark:text-gray-100'>
|
||||||
|
自定义图标
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 预制图标选择 */}
|
||||||
|
{themeSettings.progressThumbType === 'preset' && (
|
||||||
|
<div className='space-y-3 mb-4'>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
选择内置图标
|
||||||
|
</label>
|
||||||
|
<div className='grid grid-cols-2 md:grid-cols-3 gap-3'>
|
||||||
|
{[
|
||||||
|
{ id: 'renako', name: '玲奈子', url: '/icons/q/renako.png', color: '#ec4899' },
|
||||||
|
].map((thumb) => (
|
||||||
|
<button
|
||||||
|
key={thumb.id}
|
||||||
|
type='button'
|
||||||
|
onClick={() =>
|
||||||
|
setThemeSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
progressThumbPresetId: thumb.id,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className={`relative p-4 border-2 rounded-lg transition-all ${
|
||||||
|
themeSettings.progressThumbPresetId === thumb.id
|
||||||
|
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
|
||||||
|
: 'border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className='flex flex-col items-center gap-2'>
|
||||||
|
<img
|
||||||
|
src={thumb.url}
|
||||||
|
alt={thumb.name}
|
||||||
|
className='w-12 h-12 object-contain'
|
||||||
|
onError={(e) => {
|
||||||
|
(e.target as HTMLImageElement).src = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="48" height="48"%3E%3Crect width="48" height="48" fill="%23ddd"/%3E%3Ctext x="50%25" y="50%25" text-anchor="middle" dy=".3em" fill="%23999"%3E?%3C/text%3E%3C/svg%3E';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span className='text-sm font-medium text-gray-700 dark:text-gray-300 text-center'>
|
||||||
|
{thumb.name}
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
className='w-8 h-2 rounded-full'
|
||||||
|
style={{ backgroundColor: thumb.color }}
|
||||||
|
title='进度条颜色'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{themeSettings.progressThumbPresetId === thumb.id && (
|
||||||
|
<div className='absolute top-2 right-2'>
|
||||||
|
<Check className='w-5 h-5 text-blue-600 dark:text-blue-400' />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<p className='text-xs text-gray-500 dark:text-gray-400 mt-2'>
|
||||||
|
选择玲奈子图标时,进度条将变为粉色主题
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 自定义图标URL输入 */}
|
||||||
|
{themeSettings.progressThumbType === 'custom' && (
|
||||||
|
<div className='space-y-3'>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
自定义图标URL
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400'
|
||||||
|
placeholder='例如: https://example.com/icon.png'
|
||||||
|
value={themeSettings.progressThumbCustomUrl}
|
||||||
|
onChange={(e) =>
|
||||||
|
setThemeSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
progressThumbCustomUrl: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<p className='text-xs text-gray-500 dark:text-gray-400'>
|
||||||
|
支持 PNG、JPG、GIF、WebP 格式,建议尺寸 32x32px,图片URL必须可公开访问
|
||||||
|
</p>
|
||||||
|
{themeSettings.progressThumbCustomUrl && (
|
||||||
|
<div className='mt-2 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg'>
|
||||||
|
<p className='text-xs text-gray-600 dark:text-gray-400 mb-2'>预览:</p>
|
||||||
|
<img
|
||||||
|
src={themeSettings.progressThumbCustomUrl}
|
||||||
|
alt='自定义图标预览'
|
||||||
|
className='w-12 h-12 object-contain border border-gray-300 dark:border-gray-600 rounded'
|
||||||
|
onError={(e) => {
|
||||||
|
(e.target as HTMLImageElement).style.display = 'none';
|
||||||
|
const parent = (e.target as HTMLImageElement).parentElement;
|
||||||
|
if (parent && !parent.querySelector('.error-msg')) {
|
||||||
|
const errorMsg = document.createElement('p');
|
||||||
|
errorMsg.className = 'text-xs text-red-500 error-msg';
|
||||||
|
errorMsg.textContent = '图片加载失败,请检查URL是否正确';
|
||||||
|
parent.appendChild(errorMsg);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 保存按钮 */}
|
{/* 保存按钮 */}
|
||||||
<div className='flex justify-end'>
|
<div className='flex justify-end'>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ export async function POST(request: NextRequest) {
|
|||||||
cacheMinutes,
|
cacheMinutes,
|
||||||
loginBackgroundImage,
|
loginBackgroundImage,
|
||||||
registerBackgroundImage,
|
registerBackgroundImage,
|
||||||
|
progressThumbType,
|
||||||
|
progressThumbPresetId,
|
||||||
|
progressThumbCustomUrl,
|
||||||
} = body as {
|
} = body as {
|
||||||
enableBuiltInTheme: boolean;
|
enableBuiltInTheme: boolean;
|
||||||
builtInTheme: string;
|
builtInTheme: string;
|
||||||
@@ -44,6 +47,9 @@ export async function POST(request: NextRequest) {
|
|||||||
cacheMinutes: number;
|
cacheMinutes: number;
|
||||||
loginBackgroundImage?: string;
|
loginBackgroundImage?: string;
|
||||||
registerBackgroundImage?: string;
|
registerBackgroundImage?: string;
|
||||||
|
progressThumbType?: 'default' | 'preset' | 'custom';
|
||||||
|
progressThumbPresetId?: string;
|
||||||
|
progressThumbCustomUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 参数校验
|
// 参数校验
|
||||||
@@ -118,6 +124,9 @@ export async function POST(request: NextRequest) {
|
|||||||
cacheVersion: cssChanged ? currentVersion + 1 : currentVersion,
|
cacheVersion: cssChanged ? currentVersion + 1 : currentVersion,
|
||||||
loginBackgroundImage: loginBackgroundImage?.trim() || undefined,
|
loginBackgroundImage: loginBackgroundImage?.trim() || undefined,
|
||||||
registerBackgroundImage: registerBackgroundImage?.trim() || undefined,
|
registerBackgroundImage: registerBackgroundImage?.trim() || undefined,
|
||||||
|
progressThumbType: progressThumbType || 'default',
|
||||||
|
progressThumbPresetId: progressThumbPresetId?.trim() || undefined,
|
||||||
|
progressThumbCustomUrl: progressThumbCustomUrl?.trim() || undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 写入数据库
|
// 写入数据库
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ export async function GET(request: NextRequest) {
|
|||||||
OIDCButtonText: config.SiteConfig.OIDCButtonText || '',
|
OIDCButtonText: config.SiteConfig.OIDCButtonText || '',
|
||||||
loginBackgroundImage: config.ThemeConfig?.loginBackgroundImage || '',
|
loginBackgroundImage: config.ThemeConfig?.loginBackgroundImage || '',
|
||||||
registerBackgroundImage: config.ThemeConfig?.registerBackgroundImage || '',
|
registerBackgroundImage: config.ThemeConfig?.registerBackgroundImage || '',
|
||||||
|
progressThumbType: config.ThemeConfig?.progressThumbType || 'default',
|
||||||
|
progressThumbPresetId: config.ThemeConfig?.progressThumbPresetId || '',
|
||||||
|
progressThumbCustomUrl: config.ThemeConfig?.progressThumbCustomUrl || '',
|
||||||
// AI配置(只暴露功能开关,不暴露API密钥等敏感信息)
|
// AI配置(只暴露功能开关,不暴露API密钥等敏感信息)
|
||||||
AIEnabled: config.AIConfig?.Enabled || false,
|
AIEnabled: config.AIConfig?.Enabled || false,
|
||||||
AIEnableHomepageEntry: config.AIConfig?.EnableHomepageEntry || false,
|
AIEnableHomepageEntry: config.AIConfig?.EnableHomepageEntry || false,
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ export default async function RootLayout({
|
|||||||
let xiaoyaEnabled = false;
|
let xiaoyaEnabled = false;
|
||||||
let loginBackgroundImage = '';
|
let loginBackgroundImage = '';
|
||||||
let registerBackgroundImage = '';
|
let registerBackgroundImage = '';
|
||||||
|
let progressThumbType = 'default';
|
||||||
|
let progressThumbPresetId = '';
|
||||||
|
let progressThumbCustomUrl = '';
|
||||||
let enableRegistration = false;
|
let enableRegistration = false;
|
||||||
let loginRequireTurnstile = false;
|
let loginRequireTurnstile = false;
|
||||||
let registrationRequireTurnstile = false;
|
let registrationRequireTurnstile = false;
|
||||||
@@ -115,6 +118,9 @@ export default async function RootLayout({
|
|||||||
tmdbApiKey = config.SiteConfig.TMDBApiKey || '';
|
tmdbApiKey = config.SiteConfig.TMDBApiKey || '';
|
||||||
loginBackgroundImage = config.ThemeConfig?.loginBackgroundImage || '';
|
loginBackgroundImage = config.ThemeConfig?.loginBackgroundImage || '';
|
||||||
registerBackgroundImage = config.ThemeConfig?.registerBackgroundImage || '';
|
registerBackgroundImage = config.ThemeConfig?.registerBackgroundImage || '';
|
||||||
|
progressThumbType = config.ThemeConfig?.progressThumbType || 'default';
|
||||||
|
progressThumbPresetId = config.ThemeConfig?.progressThumbPresetId || '';
|
||||||
|
progressThumbCustomUrl = config.ThemeConfig?.progressThumbCustomUrl || '';
|
||||||
enableRegistration = config.SiteConfig.EnableRegistration || false;
|
enableRegistration = config.SiteConfig.EnableRegistration || false;
|
||||||
loginRequireTurnstile = config.SiteConfig.LoginRequireTurnstile || false;
|
loginRequireTurnstile = config.SiteConfig.LoginRequireTurnstile || false;
|
||||||
registrationRequireTurnstile = config.SiteConfig.RegistrationRequireTurnstile || false;
|
registrationRequireTurnstile = config.SiteConfig.RegistrationRequireTurnstile || false;
|
||||||
@@ -178,6 +184,9 @@ export default async function RootLayout({
|
|||||||
PRIVATE_LIBRARY_ENABLED: openListEnabled || embyEnabled || xiaoyaEnabled,
|
PRIVATE_LIBRARY_ENABLED: openListEnabled || embyEnabled || xiaoyaEnabled,
|
||||||
LOGIN_BACKGROUND_IMAGE: loginBackgroundImage,
|
LOGIN_BACKGROUND_IMAGE: loginBackgroundImage,
|
||||||
REGISTER_BACKGROUND_IMAGE: registerBackgroundImage,
|
REGISTER_BACKGROUND_IMAGE: registerBackgroundImage,
|
||||||
|
PROGRESS_THUMB_TYPE: progressThumbType,
|
||||||
|
PROGRESS_THUMB_PRESET_ID: progressThumbPresetId,
|
||||||
|
PROGRESS_THUMB_CUSTOM_URL: progressThumbCustomUrl,
|
||||||
ENABLE_REGISTRATION: enableRegistration,
|
ENABLE_REGISTRATION: enableRegistration,
|
||||||
LOGIN_REQUIRE_TURNSTILE: loginRequireTurnstile,
|
LOGIN_REQUIRE_TURNSTILE: loginRequireTurnstile,
|
||||||
REGISTRATION_REQUIRE_TURNSTILE: registrationRequireTurnstile,
|
REGISTRATION_REQUIRE_TURNSTILE: registrationRequireTurnstile,
|
||||||
|
|||||||
@@ -5812,6 +5812,83 @@ function PlayPageClient() {
|
|||||||
setPlayerReady(true);
|
setPlayerReady(true);
|
||||||
console.log('[PlayPage] Player ready, triggering sync setup');
|
console.log('[PlayPage] Player ready, triggering sync setup');
|
||||||
|
|
||||||
|
// 应用进度条图标配置 - 尽早执行
|
||||||
|
const applyProgressThumbConfig = () => {
|
||||||
|
try {
|
||||||
|
const config = (window as any).RUNTIME_CONFIG;
|
||||||
|
|
||||||
|
if (!config || config.PROGRESS_THUMB_TYPE === 'default') {
|
||||||
|
// 使用默认样式,移除自定义样式
|
||||||
|
const oldStyle = document.getElementById('custom-progress-thumb-style');
|
||||||
|
if (oldStyle) oldStyle.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let thumbUrl = '';
|
||||||
|
let thumbColor = '#22c55e'; // 默认绿色
|
||||||
|
|
||||||
|
if (config.PROGRESS_THUMB_TYPE === 'preset' && config.PROGRESS_THUMB_PRESET_ID) {
|
||||||
|
const presetConfig: Record<string, { url: string; color: string }> = {
|
||||||
|
renako: { url: '/icons/q/renako.png', color: '#ec4899' }, // 粉色
|
||||||
|
};
|
||||||
|
const preset = presetConfig[config.PROGRESS_THUMB_PRESET_ID];
|
||||||
|
if (preset) {
|
||||||
|
thumbUrl = preset.url;
|
||||||
|
thumbColor = preset.color;
|
||||||
|
}
|
||||||
|
} else if (config.PROGRESS_THUMB_TYPE === 'custom' && config.PROGRESS_THUMB_CUSTOM_URL) {
|
||||||
|
thumbUrl = config.PROGRESS_THUMB_CUSTOM_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改 ArtPlayer 的主题色
|
||||||
|
if (artPlayerRef.current) {
|
||||||
|
artPlayerRef.current.theme = thumbColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thumbUrl) {
|
||||||
|
// 根据预设ID确定尺寸
|
||||||
|
let width = '30px';
|
||||||
|
let height = '30px';
|
||||||
|
let marginLeft = '-15px';
|
||||||
|
|
||||||
|
// renako 图标特殊处理(288x404比例,放大1.25倍)
|
||||||
|
if (config.PROGRESS_THUMB_TYPE === 'preset' && config.PROGRESS_THUMB_PRESET_ID === 'renako') {
|
||||||
|
width = '26.875px'; // 21.5 * 1.25
|
||||||
|
height = '37.5px'; // 30 * 1.25
|
||||||
|
marginLeft = '-13.4375px'; // 10.75 * 1.25
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态设置背景图片
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.id = 'custom-progress-thumb-style';
|
||||||
|
style.textContent = `
|
||||||
|
/* 替换默认的进度条圆点为自定义图标 */
|
||||||
|
.art-video-player .art-progress-indicator {
|
||||||
|
width: ${width} !important;
|
||||||
|
height: ${height} !important;
|
||||||
|
background-image: url('${thumbUrl}') !important;
|
||||||
|
background-size: contain !important;
|
||||||
|
background-repeat: no-repeat !important;
|
||||||
|
background-position: center !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
margin-left: ${marginLeft} !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 移除旧样式
|
||||||
|
const oldStyle = document.getElementById('custom-progress-thumb-style');
|
||||||
|
if (oldStyle) oldStyle.remove();
|
||||||
|
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[进度条图标] 应用配置失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
applyProgressThumbConfig();
|
||||||
|
|
||||||
// 添加字幕切换功能
|
// 添加字幕切换功能
|
||||||
const currentSubtitles = detailRef.current?.subtitles?.[currentEpisodeIndex] || [];
|
const currentSubtitles = detailRef.current?.subtitles?.[currentEpisodeIndex] || [];
|
||||||
if (currentSubtitles.length > 0 && artPlayerRef.current) {
|
if (currentSubtitles.length > 0 && artPlayerRef.current) {
|
||||||
|
|||||||
@@ -115,6 +115,10 @@ export interface AdminConfig {
|
|||||||
cacheVersion: number; // CSS版本号(用于缓存控制)
|
cacheVersion: number; // CSS版本号(用于缓存控制)
|
||||||
loginBackgroundImage?: string; // 登录界面背景图
|
loginBackgroundImage?: string; // 登录界面背景图
|
||||||
registerBackgroundImage?: string; // 注册界面背景图
|
registerBackgroundImage?: string; // 注册界面背景图
|
||||||
|
// 进度条图标配置
|
||||||
|
progressThumbType?: 'default' | 'preset' | 'custom'; // 图标类型
|
||||||
|
progressThumbPresetId?: string; // 预制图标ID
|
||||||
|
progressThumbCustomUrl?: string; // 自定义图标URL
|
||||||
};
|
};
|
||||||
OpenListConfig?: {
|
OpenListConfig?: {
|
||||||
Enabled: boolean; // 是否启用私人影库功能
|
Enabled: boolean; // 是否启用私人影库功能
|
||||||
|
|||||||
Reference in New Issue
Block a user