forked from 77media/video-flow
feat:回调逻辑修改
This commit is contained in:
parent
1f37369b3d
commit
79a63c4f76
@ -1,71 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
import TwitterCallbackModal from '@/components/common/TwitterCallbackModal';
|
|
||||||
|
|
||||||
export default function TwitterAuthCallbackPage() {
|
|
||||||
const router = useRouter();
|
|
||||||
const [callbackParams, setCallbackParams] = useState<{ state: string; code: string } | null>(null);
|
|
||||||
const [project, setProject] = useState<any>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// 解析回调参数
|
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
|
||||||
const state = searchParams.get('state');
|
|
||||||
const code = searchParams.get('code');
|
|
||||||
|
|
||||||
if (state && code) {
|
|
||||||
setCallbackParams({ state, code });
|
|
||||||
|
|
||||||
// 从 localStorage 获取项目信息
|
|
||||||
const storedProject = localStorage.getItem('currentShareProject');
|
|
||||||
if (storedProject) {
|
|
||||||
try {
|
|
||||||
const parsedProject = JSON.parse(storedProject);
|
|
||||||
setProject(parsedProject);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('解析项目信息失败:', error);
|
|
||||||
setProject({ project_id: '', name: '未知项目', final_video_url: '' });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setProject({ project_id: '', name: '未知项目', final_video_url: '' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理 URL 参数
|
|
||||||
const cleanUrl = window.location.pathname;
|
|
||||||
window.history.replaceState({}, document.title, cleanUrl);
|
|
||||||
} else {
|
|
||||||
// 如果没有参数,重定向到主页面
|
|
||||||
router.push('/movies');
|
|
||||||
}
|
|
||||||
}, [router]);
|
|
||||||
|
|
||||||
const handleCloseModal = () => {
|
|
||||||
// 清理 localStorage 中的临时数据
|
|
||||||
try {
|
|
||||||
localStorage.removeItem('twitterAuthCallbackPayload');
|
|
||||||
localStorage.removeItem('twitterAuthCallbackFlag');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('清理 localStorage 失败:', error);
|
|
||||||
}
|
|
||||||
setCallbackParams(null);
|
|
||||||
router.push('/movies');
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-center min-h-screen bg-gray-900 text-white">
|
|
||||||
{callbackParams && project && (
|
|
||||||
<TwitterCallbackModal
|
|
||||||
visible={true}
|
|
||||||
onClose={handleCloseModal}
|
|
||||||
project={project}
|
|
||||||
urlParams={callbackParams}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!callbackParams && (
|
|
||||||
<p>处理 Twitter 授权回调...</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,17 +1,16 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Modal, Button, Spin, QRCode } from 'antd';
|
import { Modal, Button, Spin, QRCode } from 'antd';
|
||||||
import {
|
import {
|
||||||
Youtube,
|
Youtube,
|
||||||
Instagram,
|
Instagram,
|
||||||
Share2,
|
Share2,
|
||||||
Copy,
|
Copy,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
Loader2
|
Loader2
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { baseUrl } from '@/lib/env';
|
import { shareApiUrl } from '@/lib/env';
|
||||||
import TwitterCallbackModal from './TwitterCallbackModal';
|
|
||||||
|
|
||||||
interface ShareModalProps {
|
interface ShareModalProps {
|
||||||
/** 是否显示弹框 */
|
/** 是否显示弹框 */
|
||||||
@ -89,70 +88,6 @@ const sharePlatforms: SharePlatform[] = [
|
|||||||
|
|
||||||
export default function ShareModal({ visible, onClose, project }: ShareModalProps) {
|
export default function ShareModal({ visible, onClose, project }: ShareModalProps) {
|
||||||
const [loadingPlatform, setLoadingPlatform] = useState<string | null>(null);
|
const [loadingPlatform, setLoadingPlatform] = useState<string | null>(null);
|
||||||
const [twitterCallbackVisible, setTwitterCallbackVisible] = useState(false);
|
|
||||||
const [twitterCallbackParams, setTwitterCallbackParams] = useState<{
|
|
||||||
state: string;
|
|
||||||
code: string;
|
|
||||||
} | null>(null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查 URL 参数并处理 Twitter 回调
|
|
||||||
*/
|
|
||||||
useEffect(() => {
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
|
||||||
const state = urlParams.get('state');
|
|
||||||
const code = urlParams.get('code');
|
|
||||||
|
|
||||||
// 当前就在回调路径(同窗口授权)
|
|
||||||
if (state && code && window.location.pathname.includes('/api/video-share/x/auth/callback')) {
|
|
||||||
setTwitterCallbackParams({ state, code });
|
|
||||||
setTwitterCallbackVisible(true);
|
|
||||||
const newUrl = window.location.pathname;
|
|
||||||
window.history.replaceState({}, document.title, newUrl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新窗口授权,回到非回调路径,比如 /movies?twitterCallback=true
|
|
||||||
const hasFlag = urlParams.get('twitterCallback') === 'true';
|
|
||||||
const cached = localStorage.getItem('twitterAuthCallbackPayload');
|
|
||||||
if (hasFlag && cached) {
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(cached);
|
|
||||||
if (parsed?.state && parsed?.code) {
|
|
||||||
setTwitterCallbackParams({ state: parsed.state, code: parsed.code });
|
|
||||||
setTwitterCallbackVisible(true);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
|
|
||||||
}
|
|
||||||
// 清理 URL 中的 twitterCallback 标记
|
|
||||||
const cleanUrl = window.location.pathname;
|
|
||||||
window.history.replaceState({}, document.title, cleanUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听 storage 事件(跨窗口通知)
|
|
||||||
const onStorage = (e: StorageEvent) => {
|
|
||||||
if (e.key === 'twitterAuthCallbackFlag') {
|
|
||||||
const cachedPayload = localStorage.getItem('twitterAuthCallbackPayload');
|
|
||||||
if (cachedPayload) {
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(cachedPayload);
|
|
||||||
if (parsed?.state && parsed?.code) {
|
|
||||||
setTwitterCallbackParams({ state: parsed.state, code: parsed.code });
|
|
||||||
setTwitterCallbackVisible(true);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
window.addEventListener('storage', onStorage);
|
|
||||||
return () => window.removeEventListener('storage', onStorage);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户ID
|
* 获取用户ID
|
||||||
*/
|
*/
|
||||||
@ -172,12 +107,7 @@ export default function ShareModal({ visible, onClose, project }: ShareModalProp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Twitter 平台保存项目信息到 localStorage
|
const response = await fetch(`${shareApiUrl}${apiPath}?user_id=${userId}`, {
|
||||||
if (platformName.toLowerCase().includes('twitter') || platformName.toLowerCase().includes('x')) {
|
|
||||||
localStorage.setItem('currentShareProject', JSON.stringify(project));
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(`${baseUrl}${apiPath}?user_id=${userId}`, {
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@ -336,23 +266,6 @@ export default function ShareModal({ visible, onClose, project }: ShareModalProp
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Twitter 授权回调弹框 */}
|
|
||||||
{twitterCallbackParams && (
|
|
||||||
<TwitterCallbackModal
|
|
||||||
visible={twitterCallbackVisible}
|
|
||||||
onClose={() => {
|
|
||||||
setTwitterCallbackVisible(false);
|
|
||||||
setTwitterCallbackParams(null);
|
|
||||||
// 关闭时清理临时缓存
|
|
||||||
try {
|
|
||||||
localStorage.removeItem('twitterAuthCallbackPayload');
|
|
||||||
localStorage.removeItem('twitterAuthCallbackFlag');
|
|
||||||
} catch {}
|
|
||||||
}}
|
|
||||||
project={project}
|
|
||||||
urlParams={twitterCallbackParams}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,218 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import { Modal, Button, Spin, message } from 'antd';
|
|
||||||
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
|
|
||||||
import { Loader2 } from 'lucide-react';
|
|
||||||
import { baseUrl } from '@/lib/env';
|
|
||||||
|
|
||||||
interface TwitterCallbackModalProps {
|
|
||||||
/** 是否显示弹框 */
|
|
||||||
visible: boolean;
|
|
||||||
/** 关闭弹框回调 */
|
|
||||||
onClose: () => void;
|
|
||||||
/** 项目信息 */
|
|
||||||
project: {
|
|
||||||
project_id: string;
|
|
||||||
name?: string;
|
|
||||||
final_video_url?: string;
|
|
||||||
final_simple_video_url?: string;
|
|
||||||
};
|
|
||||||
/** URL 参数 */
|
|
||||||
urlParams: {
|
|
||||||
state: string;
|
|
||||||
code: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
enum CallbackStatus {
|
|
||||||
LOADING = 'loading',
|
|
||||||
SUCCESS = 'success',
|
|
||||||
FAILED = 'failed'
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function TwitterCallbackModal({
|
|
||||||
visible,
|
|
||||||
onClose,
|
|
||||||
project,
|
|
||||||
urlParams
|
|
||||||
}: TwitterCallbackModalProps) {
|
|
||||||
const [callbackStatus, setCallbackStatus] = useState<CallbackStatus>(CallbackStatus.LOADING);
|
|
||||||
const [callbackData, setCallbackData] = useState<any>(null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理 Twitter 授权回调
|
|
||||||
*/
|
|
||||||
const handleTwitterCallback = async () => {
|
|
||||||
try {
|
|
||||||
setCallbackStatus(CallbackStatus.LOADING);
|
|
||||||
|
|
||||||
// 从localStorage获取用户信息
|
|
||||||
const currentUser = JSON.parse(localStorage.getItem('currentUser') || '{}');
|
|
||||||
const userId = currentUser.id || currentUser.userId;
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
throw new Error('用户ID不存在,请先登录');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用 Twitter 授权回调接口
|
|
||||||
const response = await fetch(`${baseUrl}/api/video-share/x/auth/callback?state=${encodeURIComponent(urlParams.state)}&code=${encodeURIComponent(urlParams.code)}`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': `Bearer ${localStorage.getItem('token') || ''}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (data.successful && data.code === 0) {
|
|
||||||
setCallbackData(data.data);
|
|
||||||
setCallbackStatus(CallbackStatus.SUCCESS);
|
|
||||||
message.success('Twitter 授权成功!');
|
|
||||||
} else {
|
|
||||||
throw new Error(data.message || 'Twitter 授权回调失败');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Twitter 授权回调失败:', error);
|
|
||||||
setCallbackStatus(CallbackStatus.FAILED);
|
|
||||||
message.error(`Twitter 授权失败: ${error instanceof Error ? error.message : '未知错误'}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 组件挂载时自动处理回调
|
|
||||||
useEffect(() => {
|
|
||||||
if (visible && urlParams.state && urlParams.code) {
|
|
||||||
handleTwitterCallback();
|
|
||||||
}
|
|
||||||
}, [visible, urlParams.state, urlParams.code]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重新尝试授权
|
|
||||||
*/
|
|
||||||
const handleRetry = () => {
|
|
||||||
setCallbackStatus(CallbackStatus.LOADING);
|
|
||||||
handleTwitterCallback();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭弹框
|
|
||||||
*/
|
|
||||||
const handleClose = () => {
|
|
||||||
setCallbackStatus(CallbackStatus.LOADING);
|
|
||||||
setCallbackData(null);
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
title={
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<div className="w-5 h-5 rounded-full bg-blue-400 flex items-center justify-center">
|
|
||||||
<span className="text-white text-xs font-bold">X</span>
|
|
||||||
</div>
|
|
||||||
<span className="text-white font-medium">Twitter 授权回调</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
open={visible}
|
|
||||||
onCancel={handleClose}
|
|
||||||
footer={null}
|
|
||||||
width={480}
|
|
||||||
className="twitter-callback-modal"
|
|
||||||
styles={{
|
|
||||||
content: {
|
|
||||||
backgroundColor: 'rgba(27, 27, 27, 0.8)',
|
|
||||||
backdropFilter: 'blur(20px)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
backgroundColor: 'rgba(27, 27, 27, 0.6)',
|
|
||||||
backdropFilter: 'blur(20px)',
|
|
||||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="space-y-6">
|
|
||||||
{/* 项目信息 */}
|
|
||||||
<div className="bg-black/20 backdrop-blur-sm rounded-lg p-4 border border-white/20">
|
|
||||||
<h3 className="text-white font-medium text-sm mb-2">
|
|
||||||
分享视频: {project.name || 'Unnamed Project'}
|
|
||||||
</h3>
|
|
||||||
<p className="text-white/50 text-xs">
|
|
||||||
视频链接: {project.final_video_url || project.final_simple_video_url || 'N/A'}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 回调状态显示 */}
|
|
||||||
<div className="flex flex-col items-center space-y-4">
|
|
||||||
{callbackStatus === CallbackStatus.LOADING && (
|
|
||||||
<>
|
|
||||||
<Loader2 className="w-12 h-12 animate-spin text-blue-400" />
|
|
||||||
<div className="text-center">
|
|
||||||
<p className="text-white font-medium mb-1">正在处理 Twitter 授权...</p>
|
|
||||||
<p className="text-white/60 text-sm">请稍候,正在验证授权信息</p>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{callbackStatus === CallbackStatus.SUCCESS && (
|
|
||||||
<>
|
|
||||||
<CheckCircleOutlined className="w-12 h-12 text-green-400" />
|
|
||||||
<div className="text-center">
|
|
||||||
<p className="text-white font-medium mb-1">授权成功!</p>
|
|
||||||
<p className="text-white/60 text-sm mb-4">
|
|
||||||
Twitter 授权已完成,可以开始分享视频
|
|
||||||
</p>
|
|
||||||
{callbackData && (
|
|
||||||
<div className="bg-green-500/10 border border-green-500/20 rounded-lg p-3 mb-4">
|
|
||||||
<p className="text-green-400 text-xs">
|
|
||||||
授权 Token: {callbackData.access_token ? '已获取' : '未获取'}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={handleClose}
|
|
||||||
className="bg-blue-500 hover:bg-blue-600 border-blue-500"
|
|
||||||
>
|
|
||||||
完成
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{callbackStatus === CallbackStatus.FAILED && (
|
|
||||||
<>
|
|
||||||
<CloseCircleOutlined className="w-12 h-12 text-red-400" />
|
|
||||||
<div className="text-center">
|
|
||||||
<p className="text-white font-medium mb-1">授权失败</p>
|
|
||||||
<p className="text-white/60 text-sm mb-4">
|
|
||||||
Twitter 授权处理失败,请重试
|
|
||||||
</p>
|
|
||||||
<div className="flex gap-2 justify-center">
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
onClick={handleRetry}
|
|
||||||
className="bg-gray-600 hover:bg-gray-700 border-gray-600"
|
|
||||||
>
|
|
||||||
重试
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
onClick={handleClose}
|
|
||||||
className="bg-gray-600 hover:bg-gray-700 border-gray-600"
|
|
||||||
>
|
|
||||||
关闭
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
57
components/common/VideoShareForm.tsx
Normal file
57
components/common/VideoShareForm.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
|
||||||
|
export const VideoShareForm: React.FC<{ onCancel: () => void; onShare: (videoUrl: string, videoName: string) => void }> = ({ onCancel, onShare }) => {
|
||||||
|
const [videoUrl, setVideoUrl] = useState('');
|
||||||
|
const [videoName, setVideoName] = useState('');
|
||||||
|
|
||||||
|
const handleShare = () => {
|
||||||
|
onShare(videoUrl, videoName);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div data-alt="video-share-form-container" className="backdrop-blur-lg bg-white/30 dark:bg-slate-900/30 rounded-lg p-6 shadow-lg">
|
||||||
|
<h2 data-alt="form-title" className="text-2xl font-bold mb-4 text-slate-800 dark:text-slate-200">转发视频</h2>
|
||||||
|
<div data-alt="form-fields" className="space-y-4">
|
||||||
|
<div data-alt="video-url-field" className="flex flex-col gap-2">
|
||||||
|
<label htmlFor="videoUrl" className="text-sm font-medium text-slate-700 dark:text-slate-300">视频链接</label>
|
||||||
|
<Input
|
||||||
|
id="videoUrl"
|
||||||
|
value={videoUrl}
|
||||||
|
onChange={(e) => setVideoUrl(e.target.value)}
|
||||||
|
placeholder="请输入视频链接"
|
||||||
|
className="bg-white/50 dark:bg-slate-800/50 border-slate-300 dark:border-slate-700 text-slate-900 dark:text-slate-100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div data-alt="video-name-field" className="flex flex-col gap-2">
|
||||||
|
<label htmlFor="videoName" className="text-sm font-medium text-slate-700 dark:text-slate-300">视频名称</label>
|
||||||
|
<Input
|
||||||
|
id="videoName"
|
||||||
|
value={videoName}
|
||||||
|
onChange={(e) => setVideoName(e.target.value)}
|
||||||
|
placeholder="请输入视频名称"
|
||||||
|
className="bg-white/50 dark:bg-slate-800/50 border-slate-300 dark:border-slate-700 text-slate-900 dark:text-slate-100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div data-alt="form-actions" className="mt-6 flex justify-end gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={onCancel}
|
||||||
|
data-alt="cancel-button"
|
||||||
|
className="border-slate-400 dark:border-slate-600 text-slate-800 dark:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800"
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleShare}
|
||||||
|
data-alt="share-button"
|
||||||
|
className="bg-blue-500 hover:bg-blue-600 text-white"
|
||||||
|
>
|
||||||
|
一键转发
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -17,6 +17,7 @@ export interface EnvConfig {
|
|||||||
javaUrl: string;
|
javaUrl: string;
|
||||||
cutUrl: string;
|
cutUrl: string;
|
||||||
cutUrlTo: string;
|
cutUrlTo: string;
|
||||||
|
shareApiUrl: string; // 新增视频转发 URL 配置
|
||||||
|
|
||||||
// Google OAuth 配置
|
// Google OAuth 配置
|
||||||
googleClientId: string;
|
googleClientId: string;
|
||||||
@ -52,6 +53,7 @@ export const getEnvConfig = (): EnvConfig => {
|
|||||||
javaUrl: process.env.NEXT_PUBLIC_JAVA_URL || 'https://77.app.java.auth.qikongjian.com',
|
javaUrl: process.env.NEXT_PUBLIC_JAVA_URL || 'https://77.app.java.auth.qikongjian.com',
|
||||||
cutUrl: process.env.NEXT_PUBLIC_CUT_URL || 'https://smartcut.api.movieflow.ai',
|
cutUrl: process.env.NEXT_PUBLIC_CUT_URL || 'https://smartcut.api.movieflow.ai',
|
||||||
cutUrlTo: process.env.NEXT_PUBLIC_CUT_URL_TO || 'https://smartcut.api.movieflow.ai',
|
cutUrlTo: process.env.NEXT_PUBLIC_CUT_URL_TO || 'https://smartcut.api.movieflow.ai',
|
||||||
|
shareApiUrl: process.env.NEXT_PUBLIC_SHARE_API_URL || 'http://39.97.48.225:8000',
|
||||||
|
|
||||||
// Google OAuth 配置
|
// Google OAuth 配置
|
||||||
googleClientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || '847079918888-o1nne8d3ij80dn20qurivo987pv07225.apps.googleusercontent.com',
|
googleClientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || '847079918888-o1nne8d3ij80dn20qurivo987pv07225.apps.googleusercontent.com',
|
||||||
@ -90,6 +92,7 @@ export const {
|
|||||||
javaUrl,
|
javaUrl,
|
||||||
cutUrl,
|
cutUrl,
|
||||||
cutUrlTo,
|
cutUrlTo,
|
||||||
|
shareApiUrl, // 新增视频转发 URL 配置
|
||||||
|
|
||||||
// Google OAuth 配置
|
// Google OAuth 配置
|
||||||
googleClientId,
|
googleClientId,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user