243 lines
12 KiB
HTML
243 lines
12 KiB
HTML
<!DOCTYPE html>
|
||||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>FreeCut 自由剪辑 · 免费开源视频编辑器</title>
|
|||
|
|
<link rel="stylesheet" href="/css/style.css">
|
|||
|
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>✂️</text></svg>">
|
|||
|
|
<meta name="description" content="FreeCut 自由剪辑 —— 完全免费开源的视频编辑器,精美特效+优秀配乐,自媒体人放心用,企业/AI短剧才付费。">
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<nav class="land-nav">
|
|||
|
|
<span class="logo">✂️ FreeCut 自由剪辑</span>
|
|||
|
|
<span class="spacer"></span>
|
|||
|
|
<span id="nav-user" style="font-size:13px"></span>
|
|||
|
|
<button class="btn small" id="nav-login">登录 / 注册</button>
|
|||
|
|
<button class="btn small ghost hidden" id="nav-logout">退出</button>
|
|||
|
|
<button class="btn small ghost hidden" id="nav-admin">后台</button>
|
|||
|
|
</nav>
|
|||
|
|
|
|||
|
|
<section class="hero">
|
|||
|
|
<h1>免费开源,<span class="grad">剪出大片</span><br>自媒体人的剪辑神器</h1>
|
|||
|
|
<p>FreeCut 是一套完全免费的在线视频编辑器:精美特效、程序化原创配乐、文字字幕、转场动画,浏览器直接出片。
|
|||
|
|
<b>个人自媒体永久免费</b>,视频制作公司与 AI 短剧批量生产才需要付费。</p>
|
|||
|
|
<div class="cta">
|
|||
|
|
<button class="btn" id="hero-start">🎬 立即开始创作</button>
|
|||
|
|
<a class="btn ghost" href="#pricing">查看免费额度</a>
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section class="features">
|
|||
|
|
<div class="feature"><div class="ic">🎨</div><h3>精美特效</h3><p>12 款一键滤镜:电影、复古、赛博、梦幻… 转场动画与文字动画任你选。</p></div>
|
|||
|
|
<div class="feature"><div class="ic">🎼</div><h3>优秀配乐</h3><p>6 大情绪原创配乐,浏览器端实时合成、零版权风险,随时商用。</p></div>
|
|||
|
|
<div class="feature"><div class="ic">✂️</div><h3>专业剪辑</h3><p>多轨道时间线、剪辑分割、拖动修剪、音量控制、画布比例(9:16/16:9/1:1)。</p></div>
|
|||
|
|
<div class="feature"><div class="ic">🔒</div><h3>本地渲染</h3><p>视频在浏览器本地编码,素材隐私不出设备,服务器只存工程文件。</p></div>
|
|||
|
|
<div class="feature"><div class="ic">💎</div><h3>个人免费</h3><p>个人自媒体每天 30 次导出额度,无水印、全功能,足够日常使用。</p></div>
|
|||
|
|
<div class="feature"><div class="ic">🌱</div><h3>开源可部署</h3><p>纯 Flask + 原生前端,开源代码随意部署,数据都在自己手里。</p></div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section class="pricing" id="pricing">
|
|||
|
|
<h2>💰 定价:普通人免费,生产方付费</h2>
|
|||
|
|
<div class="price-grid">
|
|||
|
|
<div class="price-card">
|
|||
|
|
<div class="p-name">🆓 个人免费版</div>
|
|||
|
|
<div class="p-price">¥0<small> / 永久</small></div>
|
|||
|
|
<ul>
|
|||
|
|
<li>全部功能免费使用</li>
|
|||
|
|
<li>每天 30 次导出额度(够用)</li>
|
|||
|
|
<li>无水印、可商用</li>
|
|||
|
|
<li>特效 / 配乐 / 字幕全开放</li>
|
|||
|
|
</ul>
|
|||
|
|
<button class="btn block" data-go-editor>免费开始</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="price-card hot">
|
|||
|
|
<div class="p-name">🏢 企业版</div>
|
|||
|
|
<div class="p-price">¥299<small> / 月</small></div>
|
|||
|
|
<ul>
|
|||
|
|
<li>不限量导出</li>
|
|||
|
|
<li>团队协作(规划中)</li>
|
|||
|
|
<li>优先渲染通道(规划中)</li>
|
|||
|
|
<li>商用授权 + 技术支持</li>
|
|||
|
|
</ul>
|
|||
|
|
<button class="btn block" data-apply="business">申请企业版</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="price-card">
|
|||
|
|
<div class="p-name">🎬 AI 短剧版</div>
|
|||
|
|
<div class="p-price">¥499<small> / 月</small></div>
|
|||
|
|
<ul>
|
|||
|
|
<li>不限量导出</li>
|
|||
|
|
<li>批量生产流水线(规划中)</li>
|
|||
|
|
<li>独享高速编码(规划中)</li>
|
|||
|
|
<li>商用授权 + 专属支持</li>
|
|||
|
|
</ul>
|
|||
|
|
<button class="btn block" data-apply="ai_short">申请 AI 短剧版</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section class="features" style="padding-top:0">
|
|||
|
|
<div class="feature" style="grid-column:1/-1;text-align:center"><div class="ic">🧭</div><h3>创作流程</h3><p style="margin:0 auto;max-width:640px">① 上传或选择素材 → ② 拖入时间线,点击修剪分割 → ③ 一键加特效、配乐、转场、字幕 → ④ 导出 WebM 视频,直接发布。全部在浏览器完成。</p></div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<footer class="footer">
|
|||
|
|
<div>✂️ FreeCut 自由剪辑 · 免费开源 · 个人自媒体免费,企业与 AI 短剧付费</div>
|
|||
|
|
<div style="margin-top:6px">构建于 Flask + 原生 JS + Web Audio / Canvas / MediaRecorder · 浏览器本地渲染</div>
|
|||
|
|
<div style="margin-top:6px">© 2026 FreeCut · 开源协议(MIT)· 部署:<a href="/admin">管理后台</a></div>
|
|||
|
|
</footer>
|
|||
|
|
|
|||
|
|
<!-- 登录/注册弹窗 -->
|
|||
|
|
<div class="modal-mask hidden" id="auth-modal">
|
|||
|
|
<div class="modal">
|
|||
|
|
<h3 id="auth-title">登录 FreeCut</h3>
|
|||
|
|
<div class="row"><label>用户名</label><input id="auth-user" autocomplete="username"></div>
|
|||
|
|
<div class="row"><label>密码</label><input id="auth-pass" type="password" autocomplete="current-password"></div>
|
|||
|
|
<div class="row hidden" id="auth-nick-row"><label>昵称</label><input id="auth-nick"></div>
|
|||
|
|
<div id="auth-err" class="muted" style="color:var(--err);font-size:12px;min-height:16px"></div>
|
|||
|
|
<button class="btn block" id="auth-submit">登录</button>
|
|||
|
|
<p class="muted" style="text-align:center;margin-top:10px;font-size:12px">没有账号?<a href="#" id="auth-switch">注册一个(免费)</a></p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 申请企业/AI版弹窗 -->
|
|||
|
|
<div class="modal-mask hidden" id="apply-modal">
|
|||
|
|
<div class="modal">
|
|||
|
|
<h3 id="apply-title">申请开通</h3>
|
|||
|
|
<div class="row" id="apply-desc" class="muted" style="font-size:13px"></div>
|
|||
|
|
<div class="row"><label>联系方式(邮箱/微信/电话)</label><input id="apply-contact" placeholder="管理员审核通过后开通"></div>
|
|||
|
|
<div id="apply-err" class="muted" style="color:var(--err);font-size:12px;min-height:16px"></div>
|
|||
|
|
<div style="display:flex;gap:10px;justify-content:flex-end">
|
|||
|
|
<button class="btn ghost" id="apply-close">取消</button>
|
|||
|
|
<button class="btn" id="apply-submit">提交申请</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script src="/js/common.js"></script>
|
|||
|
|
<script>
|
|||
|
|
(() => {
|
|||
|
|
let mode = 'login';
|
|||
|
|
let me = null;
|
|||
|
|
const $ = s => document.querySelector(s);
|
|||
|
|
|
|||
|
|
function updateNav() {
|
|||
|
|
if (me) {
|
|||
|
|
$('#nav-user').textContent = `👤 ${me.nickname} · ${me.tier_name}`;
|
|||
|
|
$('#nav-login').classList.add('hidden');
|
|||
|
|
$('#nav-logout').classList.remove('hidden');
|
|||
|
|
if (me.username === 'admin') $('#nav-admin').classList.remove('hidden');
|
|||
|
|
else $('#nav-admin').classList.add('hidden');
|
|||
|
|
} else {
|
|||
|
|
$('#nav-user').textContent = '';
|
|||
|
|
$('#nav-login').classList.remove('hidden');
|
|||
|
|
$('#nav-logout').classList.add('hidden');
|
|||
|
|
$('#nav-admin').classList.add('hidden');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function loadMe() {
|
|||
|
|
try { const r = await FC.api('/api/me'); me = { ...r.quota, username: r.quota.username }; updateNav(); }
|
|||
|
|
catch (e) { me = null; updateNav(); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function openAuth(m) {
|
|||
|
|
mode = m || 'login';
|
|||
|
|
$('#auth-title').textContent = mode === 'login' ? '登录 FreeCut' : '注册 FreeCut(免费)';
|
|||
|
|
$('#auth-submit').textContent = mode === 'login' ? '登录' : '注册并开始';
|
|||
|
|
$('#auth-nick-row').classList.toggle('hidden', mode === 'login');
|
|||
|
|
$('#auth-err').textContent = '';
|
|||
|
|
$('#auth-modal').classList.remove('hidden');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function goEditor() {
|
|||
|
|
if (!me) { openAuth('register'); FC.toast('请先注册(免费)'); return; }
|
|||
|
|
try {
|
|||
|
|
const r = await FC.api('/api/projects', { method: 'POST', body: { name: '我的新作品' } });
|
|||
|
|
location.href = '/editor?id=' + r.id;
|
|||
|
|
} catch (e) { FC.toast(e.message, 'err'); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function renderProjects(list) {
|
|||
|
|
const grid = $('#proj-grid');
|
|||
|
|
if (!grid) return;
|
|||
|
|
if (!list.length) {
|
|||
|
|
grid.innerHTML = '<div class="empty">还没有作品,点右上角「新建作品」开始创作 ✂️</div>';
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
grid.innerHTML = list.map(p => `
|
|||
|
|
<div class="proj-card" data-id="${p.id}">
|
|||
|
|
${p.thumb ? `<img class="proj-thumb" src="${p.thumb}" style="width:100%;aspect-ratio:16/9;object-fit:cover">` : '<div class="proj-thumb">🎬</div>'}
|
|||
|
|
<div class="proj-info"><div class="t">${FC.esc(p.name)}</div><div class="s">${new Date(p.updated_at * 1000).toLocaleString()}</div></div>
|
|||
|
|
</div>`).join('');
|
|||
|
|
grid.querySelectorAll('.proj-card').forEach(c => c.addEventListener('click', () => {
|
|||
|
|
location.href = '/editor?id=' + c.dataset.id;
|
|||
|
|
}));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function loadProjects() {
|
|||
|
|
const r = await FC.api('/api/projects');
|
|||
|
|
renderProjects(r.projects);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 首页加载后如果有账号显示作品区
|
|||
|
|
async function boot() {
|
|||
|
|
await loadMe();
|
|||
|
|
if (me) {
|
|||
|
|
const sec = document.createElement('section');
|
|||
|
|
sec.className = 'app-shell';
|
|||
|
|
sec.innerHTML = `<h2 style="display:flex;align-items:center;gap:12px">📁 我的作品 <button class="btn small" id="new-proj">+ 新建作品</button></h2><div class="proj-grid" id="proj-grid"></div>`;
|
|||
|
|
document.querySelector('.features').after(sec);
|
|||
|
|
$('#new-proj').addEventListener('click', goEditor);
|
|||
|
|
loadProjects();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|||
|
|
boot();
|
|||
|
|
$('#nav-login').addEventListener('click', () => openAuth('login'));
|
|||
|
|
$('#nav-logout').addEventListener('click', async () => { await FC.api('/api/auth/logout', { method: 'POST' }); me = null; updateNav(); location.reload(); });
|
|||
|
|
$('#nav-admin').addEventListener('click', () => location.href = '/admin');
|
|||
|
|
$('#hero-start').addEventListener('click', goEditor);
|
|||
|
|
document.querySelectorAll('[data-go-editor]').forEach(b => b.addEventListener('click', goEditor));
|
|||
|
|
// 认证
|
|||
|
|
$('#auth-switch').addEventListener('click', e => { e.preventDefault(); mode = mode === 'login' ? 'register' : 'login'; openAuth(mode); });
|
|||
|
|
$('#auth-submit').addEventListener('click', async () => {
|
|||
|
|
const user = $('#auth-user').value.trim(), pass = $('#auth-pass').value, nick = $('#auth-nick').value.trim();
|
|||
|
|
$('#auth-err').textContent = '';
|
|||
|
|
try {
|
|||
|
|
if (mode === 'login') {
|
|||
|
|
await FC.api('/api/auth/login', { method: 'POST', body: { username: user, password: pass } });
|
|||
|
|
} else {
|
|||
|
|
await FC.api('/api/auth/register', { method: 'POST', body: { username: user, password: pass, nickname: nick } });
|
|||
|
|
await FC.api('/api/auth/login', { method: 'POST', body: { username: user, password: pass } });
|
|||
|
|
}
|
|||
|
|
$('#auth-modal').classList.add('hidden');
|
|||
|
|
FC.toast('欢迎回来!开始创作吧 🎉', 'ok');
|
|||
|
|
location.reload();
|
|||
|
|
} catch (e) { $('#auth-err').textContent = e.message; }
|
|||
|
|
});
|
|||
|
|
$('#auth-pass').addEventListener('keydown', e => { if (e.key === 'Enter') $('#auth-submit').click(); });
|
|||
|
|
// 申请
|
|||
|
|
let applyTier = 'business';
|
|||
|
|
document.querySelectorAll('[data-apply]').forEach(b => b.addEventListener('click', () => {
|
|||
|
|
if (!me) { openAuth('register'); return; }
|
|||
|
|
applyTier = b.dataset.apply;
|
|||
|
|
const isBiz = applyTier === 'business';
|
|||
|
|
$('#apply-title').textContent = isBiz ? '🏢 申请企业版' : '🎬 申请 AI 短剧版';
|
|||
|
|
$('#apply-desc').textContent = isBiz ? '企业版 ¥299/月 · 不限量导出、商用授权、团队协作(规划中)' : 'AI短剧版 ¥499/月 · 不限量导出、批量生产流水线(规划中)、商用授权';
|
|||
|
|
$('#apply-err').textContent = '';
|
|||
|
|
$('#apply-modal').classList.remove('hidden');
|
|||
|
|
}));
|
|||
|
|
$('#apply-close').addEventListener('click', () => $('#apply-modal').classList.add('hidden'));
|
|||
|
|
$('#apply-submit').addEventListener('click', async () => {
|
|||
|
|
try {
|
|||
|
|
await FC.api('/api/upgrade/apply', { method: 'POST', body: { tier: applyTier, contact: $('#apply-contact').value.trim() } });
|
|||
|
|
$('#apply-modal').classList.add('hidden');
|
|||
|
|
FC.toast('申请已提交,管理员审核通过后自动开通 ✅', 'ok');
|
|||
|
|
} catch (e) { $('#apply-err').textContent = e.message; }
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
})();
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|