feat: support upstash redis

This commit is contained in:
shinya
2025-07-25 18:55:21 +08:00
parent e87544a933
commit ac1cd7b148
7 changed files with 416 additions and 62 deletions

View File

@@ -130,6 +130,9 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
const isD1Storage =
typeof window !== 'undefined' &&
(window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'd1';
const isUpstashStorage =
typeof window !== 'undefined' &&
(window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'upstash';
useEffect(() => {
if (config?.UserConfig) {
@@ -292,7 +295,7 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
<div className='flex items-center justify-between'>
<label
className={`text-gray-700 dark:text-gray-300 ${
isD1Storage ? 'opacity-50' : ''
isD1Storage || isUpstashStorage ? 'opacity-50' : ''
}`}
>
@@ -301,18 +304,28 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
(D1 )
</span>
)}
{isUpstashStorage && (
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
(Upstash )
</span>
)}
</label>
<button
onClick={() =>
!isD1Storage &&
!isUpstashStorage &&
toggleAllowRegister(!userSettings.enableRegistration)
}
disabled={isD1Storage}
disabled={isD1Storage || isUpstashStorage}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${
userSettings.enableRegistration
? 'bg-green-600'
: 'bg-gray-200 dark:bg-gray-700'
} ${isD1Storage ? 'opacity-50 cursor-not-allowed' : ''}`}
} ${
isD1Storage || isUpstashStorage
? 'opacity-50 cursor-not-allowed'
: ''
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
@@ -953,10 +966,13 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
// 保存状态
const [saving, setSaving] = useState(false);
// 检测存储类型是否为 d1
// 检测存储类型是否为 d1 或 upstash
const isD1Storage =
typeof window !== 'undefined' &&
(window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'd1';
const isUpstashStorage =
typeof window !== 'undefined' &&
(window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'upstash';
useEffect(() => {
if (config?.SiteConfig) {
@@ -1004,7 +1020,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
<div>
<label
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${
isD1Storage ? 'opacity-50' : ''
isD1Storage || isUpstashStorage ? 'opacity-50' : ''
}`}
>
@@ -1013,17 +1029,25 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
(D1 )
</span>
)}
{isUpstashStorage && (
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
(Upstash )
</span>
)}
</label>
<input
type='text'
value={siteSettings.SiteName}
onChange={(e) =>
!isD1Storage &&
!isUpstashStorage &&
setSiteSettings((prev) => ({ ...prev, SiteName: e.target.value }))
}
disabled={isD1Storage}
disabled={isD1Storage || isUpstashStorage}
className={`w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent ${
isD1Storage ? 'opacity-50 cursor-not-allowed' : ''
isD1Storage || isUpstashStorage
? 'opacity-50 cursor-not-allowed'
: ''
}`}
/>
</div>
@@ -1032,7 +1056,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
<div>
<label
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${
isD1Storage ? 'opacity-50' : ''
isD1Storage || isUpstashStorage ? 'opacity-50' : ''
}`}
>
@@ -1041,20 +1065,28 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
(D1 )
</span>
)}
{isUpstashStorage && (
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
(Upstash )
</span>
)}
</label>
<textarea
value={siteSettings.Announcement}
onChange={(e) =>
!isD1Storage &&
!isUpstashStorage &&
setSiteSettings((prev) => ({
...prev,
Announcement: e.target.value,
}))
}
disabled={isD1Storage}
disabled={isD1Storage || isUpstashStorage}
rows={3}
className={`w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent ${
isD1Storage ? 'opacity-50 cursor-not-allowed' : ''
isD1Storage || isUpstashStorage
? 'opacity-50 cursor-not-allowed'
: ''
}`}
/>
</div>
@@ -1101,7 +1133,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
<div>
<label
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${
isD1Storage ? 'opacity-50' : ''
isD1Storage || isUpstashStorage ? 'opacity-50' : ''
}`}
>
@@ -1110,6 +1142,11 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
(D1 )
</span>
)}
{isUpstashStorage && (
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
(Upstash )
</span>
)}
</label>
<input
type='text'
@@ -1117,14 +1154,17 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
value={siteSettings.ImageProxy}
onChange={(e) =>
!isD1Storage &&
!isUpstashStorage &&
setSiteSettings((prev) => ({
...prev,
ImageProxy: e.target.value,
}))
}
disabled={isD1Storage}
disabled={isD1Storage || isUpstashStorage}
className={`w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent ${
isD1Storage ? 'opacity-50 cursor-not-allowed' : ''
isD1Storage || isUpstashStorage
? 'opacity-50 cursor-not-allowed'
: ''
}`}
/>
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
@@ -1136,9 +1176,9 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
<div className='flex justify-end'>
<button
onClick={handleSave}
disabled={saving || isD1Storage}
disabled={saving || isD1Storage || isUpstashStorage}
className={`px-4 py-2 ${
saving || isD1Storage
saving || isD1Storage || isUpstashStorage
? 'bg-gray-400 cursor-not-allowed'
: 'bg-green-600 hover:bg-green-700'
} text-white rounded-lg transition-colors`}

View File

@@ -14,7 +14,10 @@ const inter = Inter({ subsets: ['latin'] });
// 动态生成 metadata支持配置更新后的标题变化
export async function generateMetadata(): Promise<Metadata> {
let siteName = process.env.SITE_NAME || 'MoonTV';
if (process.env.NEXT_PUBLIC_STORAGE_TYPE !== 'd1') {
if (
process.env.NEXT_PUBLIC_STORAGE_TYPE !== 'd1' &&
process.env.NEXT_PUBLIC_STORAGE_TYPE !== 'upstash'
) {
const config = await getConfig();
siteName = config.SiteConfig.SiteName;
}
@@ -41,7 +44,10 @@ export default async function RootLayout({
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。';
let enableRegister = process.env.NEXT_PUBLIC_ENABLE_REGISTER === 'true';
let imageProxy = process.env.NEXT_PUBLIC_IMAGE_PROXY || '';
if (process.env.NEXT_PUBLIC_STORAGE_TYPE !== 'd1') {
if (
process.env.NEXT_PUBLIC_STORAGE_TYPE !== 'd1' &&
process.env.NEXT_PUBLIC_STORAGE_TYPE !== 'upstash'
) {
const config = await getConfig();
siteName = config.SiteConfig.SiteName;
announcement = config.SiteConfig.Announcement;

View File

@@ -1259,7 +1259,10 @@ function PlayPageClient() {
const now = Date.now();
if (
now - lastSaveTimeRef.current >
(process.env.NEXT_PUBLIC_STORAGE_TYPE === 'd1' ? 10000 : 5000)
(process.env.NEXT_PUBLIC_STORAGE_TYPE === 'd1' ||
process.env.NEXT_PUBLIC_STORAGE_TYPE === 'upstash'
? 10000
: 5000)
) {
saveCurrentPlayProgress();
lastSaveTimeRef.current = now;