(null);
// ====== 统一控制状态 ======
const [isPlaying, setIsPlaying] = useState(true); // 视频=播放;图文=是否自动切换
const [isFullscreen, setIsFullscreen] = useState(false);
- const [volume, setVolume] = useState(1); // 视频音量 / 图文BGM音量
- const [rate, setRate] = useState(1); // 仅视频使用
+ const [volume, setVolume] = useState(() => {
+ // 从 localStorage 读取音量,默认 1
+ if (typeof window === "undefined") return 1;
+ const saved = localStorage.getItem("aweme_player_volume");
+ if (!saved) return 1;
+ const parsed = parseFloat(saved);
+ return Number.isNaN(parsed) ? 1 : Math.max(0, Math.min(1, parsed));
+ });
+ const [rate, setRate] = useState(() => {
+ // 从 localStorage 读取倍速,默认 1
+ if (typeof window === "undefined") return 1;
+ const saved = localStorage.getItem("aweme_player_rate");
+ if (!saved) return 1;
+ const parsed = parseFloat(saved);
+ return Number.isNaN(parsed) ? 1 : parsed;
+ });
const [progress, setProgress] = useState(0); // 0..1 总进度
const [rotation, setRotation] = useState(0); // 视频旋转角度:0/90/180/270
+ const [progressRestored, setProgressRestored] = useState(false); // 标记进度是否已恢复
+ const [objectFit, setObjectFit] = useState<"contain" | "cover">("contain"); // 媒体显示模式
// ====== 图文专用(分段) ======
const images = (data as any).images as ImageData["images"] | undefined;
@@ -80,6 +164,104 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
useEffect(() => { idxRef.current = idx; }, [idx]);
+ // ====== 持久化音量到 localStorage ======
+ useEffect(() => {
+ if (typeof window === "undefined") return;
+ localStorage.setItem("aweme_player_volume", volume.toString());
+ }, [volume]);
+
+ // ====== 持久化倍速到 localStorage ======
+ useEffect(() => {
+ if (typeof window === "undefined") return;
+ localStorage.setItem("aweme_player_rate", rate.toString());
+ }, [rate]);
+
+ // ====== 持久化评论区状态到 localStorage ======
+ useEffect(() => {
+ if (typeof window === "undefined") return;
+ localStorage.setItem("aweme_player_comments_open", open.toString());
+ }, [open]);
+
+ // ====== 恢复视频播放进度(带有效期) ======
+ useEffect(() => {
+ if (!isVideo || progressRestored) return;
+ const v = videoRef.current;
+ if (!v) return;
+
+ const onLoadedMetadata = () => {
+ if (progressRestored) return;
+
+ try {
+ const key = `aweme_progress_${data.aweme_id}`;
+ const saved = localStorage.getItem(key);
+ if (!saved) {
+ setProgressRestored(true);
+ return;
+ }
+
+ const { time, timestamp } = JSON.parse(saved);
+ const now = Date.now();
+ const fiveMinutes = 5 * 60 * 1000;
+
+ // 检查是否在 5 分钟有效期内
+ if (now - timestamp < fiveMinutes && time > 1 && time < v.duration - 1) {
+ v.currentTime = time;
+ console.log(`恢复播放进度: ${Math.round(time)}s`);
+ } else if (now - timestamp >= fiveMinutes) {
+ // 过期则清除
+ localStorage.removeItem(key);
+ }
+ } catch (e) {
+ console.error("恢复播放进度失败", e);
+ }
+
+ setProgressRestored(true);
+ };
+
+ if (v.readyState >= 1) {
+ // 元数据已加载
+ onLoadedMetadata();
+ } else {
+ v.addEventListener("loadedmetadata", onLoadedMetadata, { once: true });
+ return () => v.removeEventListener("loadedmetadata", onLoadedMetadata);
+ }
+ }, [isVideo, data.aweme_id, progressRestored]);
+
+ // ====== 实时保存视频播放进度到 localStorage ======
+ useEffect(() => {
+ if (!isVideo) return;
+ const v = videoRef.current;
+ if (!v) return;
+
+ const saveProgress = () => {
+ if (!v.duration || Number.isNaN(v.duration) || v.currentTime < 1) return;
+
+ try {
+ const key = `aweme_progress_${data.aweme_id}`;
+ const value = JSON.stringify({
+ time: v.currentTime,
+ timestamp: Date.now(),
+ });
+ localStorage.setItem(key, value);
+ } catch (e) {
+ console.error("保存播放进度失败", e);
+ }
+ };
+
+ // 每 2 秒保存一次进度
+ const interval = setInterval(saveProgress, 2000);
+
+ // 页面卸载时也保存一次
+ const onBeforeUnload = () => saveProgress();
+ window.addEventListener("beforeunload", onBeforeUnload);
+
+ return () => {
+ clearInterval(interval);
+ window.removeEventListener("beforeunload", onBeforeUnload);
+ saveProgress(); // 组件卸载时保存
+ };
+ }, [isVideo, data.aweme_id]);
+
// ====== 视频:进度/播放/倍速/音量 ======
useEffect(() => {
if (!isVideo) return;
@@ -143,6 +325,30 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
return () => document.removeEventListener("fullscreenchange", onFsChange);
}, []);
+ // ====== 监听浏览器返回事件,尝试关闭页面 ======
+ useEffect(() => {
+ // 在 history 中添加一个状态,用于拦截返回事件
+ window.history.pushState({ interceptBack: true }, "");
+
+ const handlePopState = (e: PopStateEvent) => {
+ // 尝试关闭窗口
+ window.close();
+
+ // 如果关闭失败(100ms 后页面仍可见),则导航到首页
+ setTimeout(() => {
+ if (!document.hidden) {
+ router.push("/");
+ }
+ }, 100);
+ };
+
+ window.addEventListener("popstate", handlePopState);
+
+ return () => {
+ window.removeEventListener("popstate", handlePopState);
+ };
+ }, [router]);
+
// ====== 图文:自动切页(消除“闪回”)======
useEffect(() => {
if (isVideo || !images?.length) return;
@@ -241,14 +447,14 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
if (isVideo) {
const v = videoRef.current;
if (!v) return;
- if (v.paused) await v.play();
+ if (v.paused) await v.play().catch(() => { });
else v.pause();
return;
}
const el = audioRef.current;
if (!isPlaying) {
setIsPlaying(true);
- try { await el?.play(); } catch { }
+ try { await el?.play().catch(() => { }); } catch { }
} else {
setIsPlaying(false);
el?.pause();
@@ -256,10 +462,8 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
};
const toggleFullscreen = () => {
- const el = mediaContainerRef.current;
- if (!el) return;
if (!document.fullscreenElement) {
- el.requestFullscreen().catch(() => { });
+ document.body.requestFullscreen().catch(() => { });
} else {
document.exitFullscreen().catch(() => { });
}
@@ -303,8 +507,132 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
: "landscape:w-0",
].join(" ");
+ // ====== 预取上/下一条路由,提高切换流畅度 ======
+ useEffect(() => {
+ if (!neighbors) return;
+ if (neighbors.next) router.prefetch(`/aweme/${neighbors.next.aweme_id}`);
+ if (neighbors.prev) router.prefetch(`/aweme/${neighbors.prev.aweme_id}`);
+ }, [neighbors?.next?.aweme_id, neighbors?.prev?.aweme_id]);
+
+ // ====== 鼠标滚轮切换上一条/下一条(纵向滚动) ======
+ useEffect(() => {
+ const el = mediaContainerRef.current;
+ if (!el) return;
+ const onWheel = (e: WheelEvent) => {
+ // 避免缩放/横向滚动干扰
+ if (e.ctrlKey) return;
+ const now = performance.now();
+ if (now - wheelCooldownRef.current < 700) return; // 冷却 700ms
+ const dy = e.deltaY;
+ if (Math.abs(dy) < 40) return; // 过滤轻微滚轮
+
+ // 有上一条/下一条才拦截默认行为
+ if ((dy > 0 && neighbors?.next) || (dy < 0 && neighbors?.prev)) {
+ e.preventDefault();
+ }
+
+ if (dy > 0 && neighbors?.next) {
+ wheelCooldownRef.current = now;
+ router.push(`/aweme/${neighbors.next.aweme_id}`);
+ } else if (dy < 0 && neighbors?.prev) {
+ wheelCooldownRef.current = now;
+ router.push(`/aweme/${neighbors.prev.aweme_id}`);
+ }
+ };
+ // 需非被动监听以便 preventDefault
+ el.addEventListener("wheel", onWheel, { passive: false });
+ return () => el.removeEventListener("wheel", onWheel as any);
+ }, [neighbors?.next?.aweme_id, neighbors?.prev?.aweme_id]);
+
+ // ====== 动态模糊背景:每 0.2s 截取当前媒体内容绘制到背景 canvas ======
+ useEffect(() => {
+ const canvas = backgroundCanvasRef.current;
+ if (!canvas) return;
+
+ const ctx = canvas.getContext("2d");
+ if (!ctx) return;
+
+ // 更新 canvas 尺寸以匹配视口
+ const updateCanvasSize = () => {
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ };
+ updateCanvasSize();
+ window.addEventListener("resize", updateCanvasSize);
+
+ // 绘制媒体内容到 canvas(cover 策略)
+ const drawMediaToCanvas = () => {
+ if (!ctx) return;
+
+ let sourceElement: HTMLVideoElement | HTMLImageElement | null = null;
+
+ // 获取当前媒体元素
+ if (isVideo) {
+ sourceElement = videoRef.current;
+ } else {
+ // 对于图文,获取当前显示的图片
+ const scroller = scrollerRef.current;
+ if (scroller) {
+ const currentImgContainer = scroller.children[idx] as HTMLElement;
+ if (currentImgContainer) {
+ sourceElement = currentImgContainer.querySelector("img");
+ }
+ }
+ }
+
+ if (!sourceElement || (sourceElement instanceof HTMLVideoElement && sourceElement.readyState < 2)) {
+ return;
+ }
+
+ const canvasWidth = canvas.width;
+ const canvasHeight = canvas.height;
+ const sourceWidth = sourceElement instanceof HTMLVideoElement ? sourceElement.videoWidth : sourceElement.naturalWidth;
+ const sourceHeight = sourceElement instanceof HTMLVideoElement ? sourceElement.videoHeight : sourceElement.naturalHeight;
+
+ if (!sourceWidth || !sourceHeight) return;
+
+ // 计算 cover 模式的尺寸和位置
+ const canvasRatio = canvasWidth / canvasHeight;
+ const sourceRatio = sourceWidth / sourceHeight;
+
+ let drawWidth: number, drawHeight: number, offsetX: number, offsetY: number;
+
+ if (canvasRatio > sourceRatio) {
+ // canvas 更宽,按宽度填充
+ drawWidth = canvasWidth;
+ drawHeight = canvasWidth / sourceRatio;
+ offsetX = 0;
+ offsetY = (canvasHeight - drawHeight) / 2;
+ } else {
+ // canvas 更高,按高度填充
+ drawHeight = canvasHeight;
+ drawWidth = canvasHeight * sourceRatio;
+ offsetX = (canvasWidth - drawWidth) / 2;
+ offsetY = 0;
+ }
+
+ // 清空画布并绘制
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
+ ctx.drawImage(sourceElement, offsetX, offsetY, drawWidth, drawHeight);
+ };
+
+ const intervalId = setInterval(drawMediaToCanvas, 20);
+
+ return () => {
+ clearInterval(intervalId);
+ window.removeEventListener("resize", updateCanvasSize);
+ };
+ }, [isVideo, idx]);
+
return (
+ {/* 动态模糊背景 canvas */}
+
+
{/* 横屏下使用并排布局;竖屏下为单栏(评论为 bottom sheet) */}
{/* 主媒体区域 */}
@@ -317,11 +645,11 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
ref={videoRef}
src={(data as VideoData).video_url}
className={[
- // 旋转 0/180:充满容器盒子,用 object-contain;
- // 旋转 90/270:用中心定位 + 100vh/100vw + object-cover,保证铺满全屏
+ // 旋转 0/180:充满容器盒子;
+ // 旋转 90/270:用中心定位 + 100vh/100vw,保证铺满全屏
rotation % 180 === 0
- ? "absolute inset-0 h-full w-full object-contain bg-black/70"
- : "absolute top-1/2 left-1/2 h-[100vw] w-[100vh] object-contain bg-black/70",
+ ? `absolute inset-0 h-full w-full object-${objectFit} bg-black/70 cursor-pointer`
+ : `absolute top-1/2 left-1/2 h-[100vw] w-[100vh] object-${objectFit} bg-black/70 cursor-pointer`,
].join(" ")}
style={{
transform:
@@ -332,7 +660,7 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
}}
playsInline
autoPlay
- loop
+ loop onClick={togglePlay}
/>
) : (
@@ -347,7 +675,7 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
style={{ aspectRatio: img.width && img.height ? `${img.width}/${img.height}` : undefined }}
>
{/* eslint-disable-next-line @next/next/no-img-element */}
-
+
))}
@@ -506,6 +834,14 @@ export default function AwemeDetailClient(props: { data: VideoData | ImageData }
+ setObjectFit((f) => (f === "contain" ? "cover" : "contain"))}
+ aria-label={objectFit === "contain" ? "切换到填充模式" : "切换到适应模式"}
+ title={objectFit === "contain" ? "切换到填充模式" : "切换到适应模式"}
+ >
+ {objectFit === "contain" ? : }
+
{c.user.nickname}
{new Date(c.created_at).toLocaleString()}
- {c.text}
+
+
+
{c.digg_count}
diff --git a/app/aweme/[awemeId]/emojis.ts b/app/aweme/[awemeId]/emojis.ts
new file mode 100644
index 0000000..f716652
--- /dev/null
+++ b/app/aweme/[awemeId]/emojis.ts
@@ -0,0 +1,3 @@
+export const emojiList = [
+ "微笑", "色", "发呆", "酷拽", "抠鼻", "流泪", "捂脸", "发怒", "呲牙", "尬笑", "害羞", "调皮", "舔屏", "看", "爱心", "比心", "赞", "鼓掌", "感谢", "抱抱你", "玫瑰", "尴尬流汗", "戳手手", "星星眼", "杀马特", "黄脸干杯", "抱紧自己", "拜拜", "热化了", "黄脸祈祷", "懵", "举手", "加功德", "摊手", "无语流汗", "续火花吧", "点火", "哭哭", "吐舌小狗", "送花", "爱心手", "贴贴", "灵机一动", "耶", "打脸", "大笑", "机智", "送心", "666", "闭嘴", "来看我", "一起加油", "哈欠", "震惊", "晕", "衰", "困", "疑问", "泣不成声", "小鼓掌", "大金牙", "偷笑", "石化", "思考", "吐血", "可怜", "嘘", "撇嘴", "笑哭", "奸笑", "得意", "憨笑", "坏笑", "抓狂", "泪奔", "钱", "恐惧", "愉快", "快哭了", "翻白眼", "互粉", "我想静静", "委屈", "鄙视", "飞吻", "再见", "紫薇别走", "听歌", "求抱抱", "绝望的凝视", "不失礼貌的微笑", "不看", "裂开", "干饭人", "庆祝", "吐舌", "呆无辜", "白眼", "猪头", "冷漠", "暗中观察", "二哈", "菜狗", "黑脸", "展开说说", "蜜蜂狗", "柴犬", "摸头", "皱眉", "擦汗", "红脸", "做鬼脸", "强", "如花", "吐", "惊喜", "敲打", "奋斗", "吐彩虹", "大哭", "嘿哈", "惊恐", "囧", "难过", "斜眼", "阴险", "悠闲", "咒骂", "吃瓜群众", "绿帽子", "敢怒不敢言", "求求了", "眼含热泪", "叹气", "好开心", "不是吧", "鞠躬", "躺平", "九转大肠", "不你不想", "一头乱麻", "kisskiss", "你不大行", "噢买尬", "宕机", "苦涩", "逞强落泪", "求机位-黄脸", "求机位3", "点赞", "精选", "强壮", "碰拳", "OK", "击掌", "左上", "握手", "抱拳", "勾引", "拳头", "弱", "胜利", "右边", "左边", "嘴唇", "心碎", "凋谢", "愤怒", "垃圾", "啤酒", "咖啡", "蛋糕", "礼物", "撒花", "加一", "减一", "okk", "V5", "绝", "给力", "红包", "屎", "发", "18禁", "炸弹", "西瓜", "加鸡腿", "握爪", "太阳", "月亮", "给跪了", "蕉绿", "扎心", "胡瓜", "打call", "栓Q", "雪花", "圣诞树", "平安果", "圣诞帽", "气球", "烟花", "福", "candy", "糖葫芦", "鞭炮", "元宝", "灯笼", "锦鲤", "巧克力", "戒指", "棒棒糖", "纸飞机", "粽子"
+]
\ No newline at end of file
diff --git a/app/aweme/[awemeId]/page.tsx b/app/aweme/[awemeId]/page.tsx
index eed8ff4..3e99de9 100644
--- a/app/aweme/[awemeId]/page.tsx
+++ b/app/aweme/[awemeId]/page.tsx
@@ -63,6 +63,32 @@ export default async function AwemeDetail({ params }: { params: Promise<{ awemeI
})),
};
+ // Compute prev/next neighbors by created_at across videos and image posts
+ const currentCreatedAt = (isVideo ? video!.created_at : post!.created_at) as unknown as Date;
+ const [newerVideo, newerPost, olderVideo, olderPost] = await Promise.all([
+ prisma.video.findFirst({ where: { created_at: { gt: currentCreatedAt } }, orderBy: { created_at: "asc" }, select: { aweme_id: true, created_at: true } }),
+ prisma.imagePost.findFirst({ where: { created_at: { gt: currentCreatedAt } }, orderBy: { created_at: "asc" }, select: { aweme_id: true, created_at: true } }),
+ prisma.video.findFirst({ where: { created_at: { lt: currentCreatedAt } }, orderBy: { created_at: "desc" }, select: { aweme_id: true, created_at: true } }),
+ prisma.imagePost.findFirst({ where: { created_at: { lt: currentCreatedAt } }, orderBy: { created_at: "desc" }, select: { aweme_id: true, created_at: true } }),
+ ]);
+ const pickPrev = (() => {
+ const cands: { aweme_id: string; created_at: Date }[] = [];
+ if (newerVideo) cands.push({ aweme_id: newerVideo.aweme_id, created_at: newerVideo.created_at as unknown as Date });
+ if (newerPost) cands.push({ aweme_id: newerPost.aweme_id, created_at: newerPost.created_at as unknown as Date });
+ if (cands.length === 0) return null;
+ cands.sort((a, b) => +a.created_at - +b.created_at);
+ return { aweme_id: cands[0].aweme_id };
+ })();
+ const pickNext = (() => {
+ const cands: { aweme_id: string; created_at: Date }[] = [];
+ if (olderVideo) cands.push({ aweme_id: olderVideo.aweme_id, created_at: olderVideo.created_at as unknown as Date });
+ if (olderPost) cands.push({ aweme_id: olderPost.aweme_id, created_at: olderPost.created_at as unknown as Date });
+ if (cands.length === 0) return null;
+ cands.sort((a, b) => +b.created_at - +a.created_at);
+ return { aweme_id: cands[0].aweme_id };
+ })();
+ const neighbors: { prev: { aweme_id: string } | null; next: { aweme_id: string } | null } = { prev: pickPrev, next: pickNext };
+
return (
{/* 顶部条改为悬浮在媒体区域之上,避免 sticky 造成 Y 方向滚动条 */}
@@ -72,7 +98,7 @@ export default async function AwemeDetail({ params }: { params: Promise<{ awemeI
className="inline-flex items-center justify-center w-9 h-9 rounded-full bg-white/15 text-white border border-white/20 backdrop-blur hover:bg-white/25"
/>
-
+
);
}
diff --git a/app/components/BackButton.tsx b/app/components/BackButton.tsx
index 64e8caa..a1f3015 100644
--- a/app/components/BackButton.tsx
+++ b/app/components/BackButton.tsx
@@ -14,8 +14,8 @@ type BackButtonProps = {
/**
* BackButton
- * - Primary: behaves like browser back (router.back()), preserving previous page state (e.g., scroll, filters)
- * - Fallback: if no history entry exists (e.g., opened directly), navigates to '/'
+ * - Primary: attempts to close the current window/tab (window.close())
+ * - Fallback: if close fails (e.g., not opened by script), navigates to '/'
* - Uses so that Ctrl/Cmd-click or middle-click opens the fallback URL in a new tab naturally
*/
export default function BackButton({ className, ariaLabel = '返回', hrefFallback = '/', children }: BackButtonProps) {
@@ -25,13 +25,21 @@ export default function BackButton({ className, ariaLabel = '返回', hrefFallba
// Respect modifier clicks (new tab/window) and non-left clicks
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
- // Prefer SPA back when we have some history to go back to
- if (typeof window !== 'undefined' && window.history.length > 1) {
- e.preventDefault();
- router.back();
+ e.preventDefault();
+
+ // Try to close the window first
+ if (typeof window !== 'undefined') {
+ window.close();
+
+ // If window.close() didn't work (window still open after a short delay),
+ // navigate to the fallback URL
+ setTimeout(() => {
+ if (!document.hidden) {
+ router.push(hrefFallback);
+ }
+ }, 80);
}
- // else: allow default to navigate to fallback
- }, [router]);
+ }, [router, hrefFallback]);
return (
(
-
+
| null = null
+let context: BrowserContext | null = null
+let refCount = 0
+let idleCloseTimer: NodeJS.Timeout | null = null
+
+const USER_DATA_DIR = 'chrome-profile/douyin'
+const DEFAULT_OPTIONS = { headless: true } as const
+
+async function launchContext(): Promise {
+ const ctx = await chromium.launchPersistentContext(USER_DATA_DIR, DEFAULT_OPTIONS)
+ // When the context is closed externally, reset manager state
+ ctx.on('close', () => {
+ context = null
+ contextPromise = null
+ refCount = 0
+ if (idleCloseTimer) {
+ clearTimeout(idleCloseTimer)
+ idleCloseTimer = null
+ }
+ })
+ return ctx
+}
+
+export async function acquireBrowserContext(): Promise {
+ // Cancel any pending idle close if a new consumer arrives
+ if (idleCloseTimer) {
+ clearTimeout(idleCloseTimer)
+ idleCloseTimer = null
+ }
+
+ if (context) {
+ refCount += 1
+ return context
+ }
+
+ if (!contextPromise) {
+ contextPromise = launchContext()
+ }
+ context = await contextPromise
+ refCount += 1
+ return context
+}
+
+export async function releaseBrowserContext(options?: { idleMillis?: number }): Promise {
+ const idleMillis = options?.idleMillis ?? 15_000
+ refCount = Math.max(0, refCount - 1)
+
+ if (refCount > 0 || !context) return
+
+ // Delay the close to allow bursty workloads to reuse the context
+ if (idleCloseTimer) {
+ clearTimeout(idleCloseTimer)
+ idleCloseTimer = null
+ }
+ idleCloseTimer = setTimeout(async () => {
+ try {
+ if (context && refCount === 0) {
+ await context.close()
+ }
+ } finally {
+ context = null
+ contextPromise = null
+ idleCloseTimer = null
+ }
+ }, idleMillis)
+}
diff --git a/app/fetcher/index.ts b/app/fetcher/index.ts
index 71f4d46..1b381d6 100644
--- a/app/fetcher/index.ts
+++ b/app/fetcher/index.ts
@@ -1,5 +1,5 @@
// src/scrapeDouyin.ts
-import { BrowserContext, chromium, Page, type Response } from 'playwright';
+import { BrowserContext, Page, chromium, type Response } from 'playwright';
import { prisma } from '@/lib/prisma';
import { uploadFile, generateUniqueFileName } from '@/lib/minio';
import { createCamelCompatibleProxy } from '@/app/fetcher/utils';
@@ -8,6 +8,7 @@ import { pickBestPlayAddr, extractFirstFrame } from '@/app/fetcher/media';
import { handleImagePost } from '@/app/fetcher/uploader';
import { saveToDB, saveImagePostToDB } from '@/app/fetcher/persist';
import chalk from 'chalk';
+import { acquireBrowserContext, releaseBrowserContext } from '@/app/fetcher/browser';
const DETAIL_PATH = '/aweme/v1/web/aweme/detail/';
const COMMENT_PATH = '/aweme/v1/web/comment/list/';
@@ -33,11 +34,21 @@ async function readPostMem(context: BrowserContext, page: Page) {
}
-export async function scrapeDouyin(url: string) {
- const browser = await chromium.launch({ headless: true });
- console.log(chalk.blue('🚀 启动 Chromium 浏览器...'));
+export class ScrapeError extends Error {
+ constructor(
+ message: string,
+ public statusCode: number = 500,
+ public code?: string
+ ) {
+ super(message);
+ this.name = 'ScrapeError';
+ }
+}
- const context = await chromium.launchPersistentContext('chrome-profile/douyin', { headless: false });
+export async function scrapeDouyin(url: string) {
+ console.log(chalk.blue('🚀 启动共享 Chromium 浏览器...'));
+
+ const context = await acquireBrowserContext();
const page = await context.newPage();
console.log(chalk.cyan(`📄 正在访问: ${chalk.underline(url)}`));
@@ -82,6 +93,13 @@ export async function scrapeDouyin(url: string) {
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60_000 });
+ // 查找页面中是否存在 "视频不存在" 的提示
+ const isNotFound = await page.locator('text=视频不存在').count().then(count => count > 0).catch(() => false);
+ if (isNotFound) {
+ console.error(chalk.red('✗ 视频不存在或已被删除'));
+ throw new ScrapeError('视频不存在或已被删除', 404, 'VIDEO_NOT_FOUND');
+ }
+
try {
// 优先尝试从内存读取图文数据
let { aweme, comments } = await readPostMem(context, page);
@@ -113,8 +131,8 @@ export async function scrapeDouyin(url: string) {
const firstType = await firstTypePromise;
if (!firstType) {
- console.error(chalk.red('✗ 既无法从内存读取数据,也无法从网络获得数据'));
- throw new Error('既无法从内存读取数据,也无法从网络获得数据。');
+ console.error(chalk.red('✗ 既无法从内存读取数据,也无法从网络获得数据'));
+ throw new ScrapeError('无法获取作品数据,可能是网络问题或作品已下架', 404, 'NO_DATA');
}
console.log(chalk.cyan(`📡 检测到作品类型: ${chalk.bold(firstType.key === 'post' ? '图文' : '视频')}`));
@@ -129,14 +147,14 @@ export async function scrapeDouyin(url: string) {
if (firstType.key === 'post') {
// 图文作品
const postJson = await safeJson(firstType.response);
- if (!postJson?.aweme_list?.length) throw new Error('图文作品响应为空');
+ if (!postJson?.aweme_list?.length) throw new ScrapeError('图文作品响应为空', 404, 'EMPTY_POST_RESPONSE');
const currentURL = page.url();
const target_aweme_id = currentURL.split('/').at(-1);
const awemeList = postJson.aweme_list as unknown as DouyinImageAweme[];
let aweme = awemeList.find((pt: DouyinImageAweme) => pt.aweme_id === target_aweme_id);
if (!aweme) {
- throw new Error('既无法从内存读取数据,Post 列表中也不包含需要爬取的作品。');
+ throw new ScrapeError('无法找到目标作品,可能已被删除', 404, 'POST_NOT_FOUND');
}
const uploads = await handleImagePost(context, aweme);
@@ -191,12 +209,36 @@ export async function scrapeDouyin(url: string) {
console.log(chalk.green.bold('✓ 视频作品保存成功'));
return { type: "video", ...saved };
} else {
- throw new Error('无法判定作品类型(未命中详情或图文接口)');
+ throw new ScrapeError('无法判定作品类型,接口响应异常', 500, 'UNKNOWN_TYPE');
}
+ } catch (error) {
+ // 如果是我们自定义的错误,直接抛出
+ if (error instanceof ScrapeError) {
+ throw error;
+ }
+
+ // 处理其他类型的错误
+ const errMsg = (error as Error)?.message || String(error);
+ console.error(chalk.red(`✗ 爬取失败: ${errMsg}`));
+
+ // 根据错误类型返回不同的状态码
+ if (errMsg.includes('timeout') || errMsg.includes('超时')) {
+ throw new ScrapeError('请求超时,请稍后重试', 408, 'TIMEOUT');
+ }
+ if (errMsg.includes('页面内存数据中未找到作品详情')) {
+ throw new ScrapeError('作品数据加载失败', 404, 'DATA_NOT_LOADED');
+ }
+ if (errMsg.includes('net::')) {
+ throw new ScrapeError('网络连接失败', 503, 'NETWORK_ERROR');
+ }
+
+ // 默认服务器错误
+ throw new ScrapeError(errMsg || '爬取过程中发生未知错误', 500, 'UNKNOWN_ERROR');
} finally {
console.log(chalk.gray('🧹 清理资源...'));
- await context.close();
- await browser.close();
+ try { await page.close({ runBeforeUnload: true }); } catch {}
+ // 仅释放共享上下文的引用,不直接关闭窗口
+ await releaseBrowserContext();
await prisma.$disconnect();
console.log(chalk.gray('✓ 资源清理完成'));
}
diff --git a/app/fetcher/network.ts b/app/fetcher/network.ts
index a510695..95a4cc8 100644
--- a/app/fetcher/network.ts
+++ b/app/fetcher/network.ts
@@ -22,7 +22,7 @@ export async function downloadBinary(
context: BrowserContext,
url: string
): Promise<{ buffer: Buffer; contentType: string; ext: string }> {
- console.log('Download bin:', url);
+ console.log('下载:', url);
const headers = {
referer: url,
diff --git a/app/fetcher/route.ts b/app/fetcher/route.ts
index f46cead..3a2034c 100644
--- a/app/fetcher/route.ts
+++ b/app/fetcher/route.ts
@@ -1,17 +1,49 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
-import { scrapeDouyin } from '.';
+import { scrapeDouyin, ScrapeError } from '.';
async function handleDouyinScrape(req: NextRequest) {
const { searchParams } = new URL(req.url);
const videoUrl = searchParams.get('url');
+
if (!videoUrl) {
- return NextResponse.json({ error: '缺少视频URL' }, { status: 400 });
+ return NextResponse.json(
+ { error: '缺少视频URL', code: 'MISSING_URL' },
+ { status: 400 }
+ );
}
- // 调用爬虫函数
- const result = await scrapeDouyin(videoUrl);
- return NextResponse.json(result);
+ try {
+ // 调用爬虫函数
+ const result = await scrapeDouyin(videoUrl);
+ return NextResponse.json({
+ success: true,
+ data: result
+ });
+ } catch (error) {
+ // 处理自定义的 ScrapeError
+ if (error instanceof ScrapeError) {
+ return NextResponse.json(
+ {
+ success: false,
+ error: error.message,
+ code: error.code
+ },
+ { status: error.statusCode }
+ );
+ }
+
+ // 处理未知错误
+ console.error('未捕获的错误:', error);
+ return NextResponse.json(
+ {
+ success: false,
+ error: '服务器内部错误',
+ code: 'INTERNAL_ERROR'
+ },
+ { status: 500 }
+ );
+ }
}
export const GET = handleDouyinScrape
diff --git a/app/tasks/page.tsx b/app/tasks/page.tsx
index cf6a0e0..e069cd5 100644
--- a/app/tasks/page.tsx
+++ b/app/tasks/page.tsx
@@ -32,6 +32,7 @@ export default function TasksPage() {
const [tasks, setTasks] = useState([]);
const controllers = useRef>(new Map());
const [openDetails, setOpenDetails] = useState>(new Set());
+ const [, setTick] = useState(0); // 用于强制更新计时显示
const inProgressUrls = useMemo(
() => new Set(tasks.filter(t => t.status === "pending" || t.status === "running").map(t => t.url)),
@@ -44,12 +45,13 @@ export default function TasksPage() {
setTasks((prev) => {
const existing = new Set(prev.map((t) => t.id));
const notDuplicated = urls.filter(u => !inProgressUrls.has(u));
- const next: Task[] = [...prev];
+ const newTasks: Task[] = [];
for (const url of notDuplicated) {
const id = `${now}-${Math.random().toString(36).slice(2, 8)}`;
- next.push({ id, url, status: "pending" });
+ newTasks.push({ id, url, status: "pending" });
}
- return next;
+ // 新任务添加到最前面
+ return [...newTasks, ...prev];
});
}, [inProgressUrls]);
@@ -69,14 +71,18 @@ export default function TasksPage() {
if (controllers.current.has(task.id)) return;
const ctrl = new AbortController();
controllers.current.set(task.id, ctrl);
- setTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: "running", startedAt: Date.now() } : t));
+ setTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: "running", startedAt: Date.now(), error: undefined } : t));
try {
const res = await fetch(`/fetcher?url=${encodeURIComponent(task.url)}`, { signal: ctrl.signal, method: "GET" });
+ const data = await res.json().catch(() => null);
+
if (!res.ok) {
- const text = await res.text().catch(() => "");
- throw new Error(text || `请求失败: ${res.status}`);
+ // 使用后端返回的结构化错误信息
+ const errorMsg = data?.error || `请求失败: ${res.status}`;
+ const errorCode = data?.code || 'UNKNOWN';
+ throw new Error(`${errorMsg} (${errorCode})`);
}
- const data = await res.json().catch(() => undefined);
+
setTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: "success", finishedAt: Date.now(), result: data } : t));
} catch (err: any) {
const msg = err?.name === 'AbortError' ? '已取消' : (err?.message || String(err));
@@ -92,12 +98,33 @@ export default function TasksPage() {
pending.forEach((t) => startTask(t));
}, [tasks, startTask]);
+ // 定时器更新运行中任务的耗时显示
+ useEffect(() => {
+ const hasRunningTasks = tasks.some(t => t.status === "running");
+ if (!hasRunningTasks) return;
+
+ const timer = setInterval(() => {
+ setTick(prev => prev + 1);
+ }, 1000); // 每秒更新一次
+
+ return () => clearInterval(timer);
+ }, [tasks]);
+
const cancelTask = useCallback((id: string) => {
const ctrl = controllers.current.get(id);
if (ctrl) ctrl.abort();
controllers.current.delete(id);
}, []);
+ const retryTask = useCallback((taskId: string) => {
+ setTasks(prev => prev.map(t => {
+ if (t.id === taskId) {
+ return { ...t, status: "pending" as TaskStatus, error: undefined, result: undefined };
+ }
+ return t;
+ }));
+ }, []);
+
const clearFinished = useCallback(() => {
setTasks(prev => prev.filter(t => t.status === "pending" || t.status === "running"));
}, []);
@@ -203,7 +230,25 @@ export default function TasksPage() {
-
+
+ {t.status === 'success' && t.result?.data?.aweme_id && (
+
+ 查看作品
+
+ )}
+ {t.status === 'error' && (
+
retryTask(t.id)}
+ className="inline-flex items-center gap-1 rounded-md bg-amber-600/80 px-2 py-1 text-xs text-white transition-colors hover:bg-amber-600"
+ >
+ 重试
+
+ )}
{t.status === 'running' && (
cancelTask(t.id)} className="inline-flex items-center gap-1 rounded-md bg-red-600/80 px-2 py-1 text-xs text-white transition-colors hover:bg-red-600">
取消
@@ -224,13 +269,49 @@ export default function TasksPage() {
{isOpen && (
- {t.status === 'error' && (
-
-
{t.error}
+ {t.status === 'error' && t.error && (
+
+
+
+
常见原因:
+
+ 视频已被删除或设为私密
+ 网络连接问题或请求超时
+ 抖音接口限流或反爬虫
+
+
)}
{typeof t.result !== 'undefined' && (
-
{JSON.stringify(t.result, null, 2)}
+
+ {t.result?.data?.aweme && (
+
+
+
+ 作品信息
+
+
+
ID: {t.result.data.aweme.aweme_id}
+
描述: {t.result.data.aweme.desc || '(无)'}
+ {t.result.data.aweme.author && (
+
作者: {t.result.data.aweme.author.nickname}
+ )}
+
+
+ )}
+
+
+ 查看完整响应数据 ▶ ▼
+
+ {JSON.stringify(t.result, null, 2)}
+
+
)}
{typeof t.result === 'undefined' && t.status !== 'error' && (
暂无输出
diff --git a/public/emojis/18禁.webp b/public/emojis/18禁.webp
new file mode 100644
index 0000000..4798cb3
Binary files /dev/null and b/public/emojis/18禁.webp differ
diff --git a/public/emojis/666.webp b/public/emojis/666.webp
new file mode 100644
index 0000000..a047c4c
Binary files /dev/null and b/public/emojis/666.webp differ
diff --git a/public/emojis/OK.webp b/public/emojis/OK.webp
new file mode 100644
index 0000000..1345647
Binary files /dev/null and b/public/emojis/OK.webp differ
diff --git a/public/emojis/V5.webp b/public/emojis/V5.webp
new file mode 100644
index 0000000..d5d9ec3
Binary files /dev/null and b/public/emojis/V5.webp differ
diff --git a/public/emojis/candy.webp b/public/emojis/candy.webp
new file mode 100644
index 0000000..c797a81
Binary files /dev/null and b/public/emojis/candy.webp differ
diff --git a/public/emojis/kisskiss.webp b/public/emojis/kisskiss.webp
new file mode 100644
index 0000000..4774b6a
Binary files /dev/null and b/public/emojis/kisskiss.webp differ
diff --git a/public/emojis/okk.webp b/public/emojis/okk.webp
new file mode 100644
index 0000000..66e4b67
Binary files /dev/null and b/public/emojis/okk.webp differ
diff --git a/public/emojis/一头乱麻.webp b/public/emojis/一头乱麻.webp
new file mode 100644
index 0000000..2dbf85a
Binary files /dev/null and b/public/emojis/一头乱麻.webp differ
diff --git a/public/emojis/一起加油.webp b/public/emojis/一起加油.webp
new file mode 100644
index 0000000..798b3e0
Binary files /dev/null and b/public/emojis/一起加油.webp differ
diff --git a/public/emojis/不你不想.webp b/public/emojis/不你不想.webp
new file mode 100644
index 0000000..23f24f4
Binary files /dev/null and b/public/emojis/不你不想.webp differ
diff --git a/public/emojis/不失礼貌的微笑.webp b/public/emojis/不失礼貌的微笑.webp
new file mode 100644
index 0000000..4f89302
Binary files /dev/null and b/public/emojis/不失礼貌的微笑.webp differ
diff --git a/public/emojis/不是吧.webp b/public/emojis/不是吧.webp
new file mode 100644
index 0000000..e09fd5d
Binary files /dev/null and b/public/emojis/不是吧.webp differ
diff --git a/public/emojis/不看.webp b/public/emojis/不看.webp
new file mode 100644
index 0000000..b826f92
Binary files /dev/null and b/public/emojis/不看.webp differ
diff --git a/public/emojis/举手.webp b/public/emojis/举手.webp
new file mode 100644
index 0000000..c964b5d
Binary files /dev/null and b/public/emojis/举手.webp differ
diff --git a/public/emojis/九转大肠.webp b/public/emojis/九转大肠.webp
new file mode 100644
index 0000000..eebc79d
Binary files /dev/null and b/public/emojis/九转大肠.webp differ
diff --git a/public/emojis/二哈.webp b/public/emojis/二哈.webp
new file mode 100644
index 0000000..0c58e17
Binary files /dev/null and b/public/emojis/二哈.webp differ
diff --git a/public/emojis/互粉.webp b/public/emojis/互粉.webp
new file mode 100644
index 0000000..b2efc3a
Binary files /dev/null and b/public/emojis/互粉.webp differ
diff --git a/public/emojis/你不大行.webp b/public/emojis/你不大行.webp
new file mode 100644
index 0000000..77c67ca
Binary files /dev/null and b/public/emojis/你不大行.webp differ
diff --git a/public/emojis/做鬼脸.webp b/public/emojis/做鬼脸.webp
new file mode 100644
index 0000000..8963711
Binary files /dev/null and b/public/emojis/做鬼脸.webp differ
diff --git a/public/emojis/偷笑.webp b/public/emojis/偷笑.webp
new file mode 100644
index 0000000..7387273
Binary files /dev/null and b/public/emojis/偷笑.webp differ
diff --git a/public/emojis/元宝.webp b/public/emojis/元宝.webp
new file mode 100644
index 0000000..149710d
Binary files /dev/null and b/public/emojis/元宝.webp differ
diff --git a/public/emojis/再见.webp b/public/emojis/再见.webp
new file mode 100644
index 0000000..771272b
Binary files /dev/null and b/public/emojis/再见.webp differ
diff --git a/public/emojis/冷漠.webp b/public/emojis/冷漠.webp
new file mode 100644
index 0000000..3670052
Binary files /dev/null and b/public/emojis/冷漠.webp differ
diff --git a/public/emojis/凋谢.webp b/public/emojis/凋谢.webp
new file mode 100644
index 0000000..732457b
Binary files /dev/null and b/public/emojis/凋谢.webp differ
diff --git a/public/emojis/减一.webp b/public/emojis/减一.webp
new file mode 100644
index 0000000..26327b5
Binary files /dev/null and b/public/emojis/减一.webp differ
diff --git a/public/emojis/击掌.webp b/public/emojis/击掌.webp
new file mode 100644
index 0000000..4245e44
Binary files /dev/null and b/public/emojis/击掌.webp differ
diff --git a/public/emojis/加一.webp b/public/emojis/加一.webp
new file mode 100644
index 0000000..ea6b9db
Binary files /dev/null and b/public/emojis/加一.webp differ
diff --git a/public/emojis/加功德.webp b/public/emojis/加功德.webp
new file mode 100644
index 0000000..de96561
Binary files /dev/null and b/public/emojis/加功德.webp differ
diff --git a/public/emojis/加鸡腿.webp b/public/emojis/加鸡腿.webp
new file mode 100644
index 0000000..1a27976
Binary files /dev/null and b/public/emojis/加鸡腿.webp differ
diff --git a/public/emojis/勾引.webp b/public/emojis/勾引.webp
new file mode 100644
index 0000000..63f3fb5
Binary files /dev/null and b/public/emojis/勾引.webp differ
diff --git a/public/emojis/发.webp b/public/emojis/发.webp
new file mode 100644
index 0000000..0d2fc1f
Binary files /dev/null and b/public/emojis/发.webp differ
diff --git a/public/emojis/发呆.webp b/public/emojis/发呆.webp
new file mode 100644
index 0000000..89ee46e
Binary files /dev/null and b/public/emojis/发呆.webp differ
diff --git a/public/emojis/发怒.webp b/public/emojis/发怒.webp
new file mode 100644
index 0000000..2864ed2
Binary files /dev/null and b/public/emojis/发怒.webp differ
diff --git a/public/emojis/可怜.webp b/public/emojis/可怜.webp
new file mode 100644
index 0000000..6f487ed
Binary files /dev/null and b/public/emojis/可怜.webp differ
diff --git a/public/emojis/右边.webp b/public/emojis/右边.webp
new file mode 100644
index 0000000..d4d6023
Binary files /dev/null and b/public/emojis/右边.webp differ
diff --git a/public/emojis/叹气.webp b/public/emojis/叹气.webp
new file mode 100644
index 0000000..33e1c2e
Binary files /dev/null and b/public/emojis/叹气.webp differ
diff --git a/public/emojis/吃瓜群众.webp b/public/emojis/吃瓜群众.webp
new file mode 100644
index 0000000..a0fd909
Binary files /dev/null and b/public/emojis/吃瓜群众.webp differ
diff --git a/public/emojis/吐.webp b/public/emojis/吐.webp
new file mode 100644
index 0000000..807206f
Binary files /dev/null and b/public/emojis/吐.webp differ
diff --git a/public/emojis/吐彩虹.webp b/public/emojis/吐彩虹.webp
new file mode 100644
index 0000000..2a921a1
Binary files /dev/null and b/public/emojis/吐彩虹.webp differ
diff --git a/public/emojis/吐舌.webp b/public/emojis/吐舌.webp
new file mode 100644
index 0000000..8c937b5
Binary files /dev/null and b/public/emojis/吐舌.webp differ
diff --git a/public/emojis/吐舌小狗.webp b/public/emojis/吐舌小狗.webp
new file mode 100644
index 0000000..825bb1c
Binary files /dev/null and b/public/emojis/吐舌小狗.webp differ
diff --git a/public/emojis/吐血.webp b/public/emojis/吐血.webp
new file mode 100644
index 0000000..9c18ad5
Binary files /dev/null and b/public/emojis/吐血.webp differ
diff --git a/public/emojis/听歌.webp b/public/emojis/听歌.webp
new file mode 100644
index 0000000..7b2bda0
Binary files /dev/null and b/public/emojis/听歌.webp differ
diff --git a/public/emojis/呆无辜.webp b/public/emojis/呆无辜.webp
new file mode 100644
index 0000000..3d615b8
Binary files /dev/null and b/public/emojis/呆无辜.webp differ
diff --git a/public/emojis/呲牙.webp b/public/emojis/呲牙.webp
new file mode 100644
index 0000000..199f42c
Binary files /dev/null and b/public/emojis/呲牙.webp differ
diff --git a/public/emojis/咒骂.webp b/public/emojis/咒骂.webp
new file mode 100644
index 0000000..03681ed
Binary files /dev/null and b/public/emojis/咒骂.webp differ
diff --git a/public/emojis/咖啡.webp b/public/emojis/咖啡.webp
new file mode 100644
index 0000000..ddae267
Binary files /dev/null and b/public/emojis/咖啡.webp differ
diff --git a/public/emojis/哈欠.webp b/public/emojis/哈欠.webp
new file mode 100644
index 0000000..58b274c
Binary files /dev/null and b/public/emojis/哈欠.webp differ
diff --git a/public/emojis/哭哭.webp b/public/emojis/哭哭.webp
new file mode 100644
index 0000000..61e6ca0
Binary files /dev/null and b/public/emojis/哭哭.webp differ
diff --git a/public/emojis/啤酒.webp b/public/emojis/啤酒.webp
new file mode 100644
index 0000000..8c57837
Binary files /dev/null and b/public/emojis/啤酒.webp differ
diff --git a/public/emojis/嘘.webp b/public/emojis/嘘.webp
new file mode 100644
index 0000000..5b7d176
Binary files /dev/null and b/public/emojis/嘘.webp differ
diff --git a/public/emojis/嘴唇.webp b/public/emojis/嘴唇.webp
new file mode 100644
index 0000000..b2cec84
Binary files /dev/null and b/public/emojis/嘴唇.webp differ
diff --git a/public/emojis/嘿哈.webp b/public/emojis/嘿哈.webp
new file mode 100644
index 0000000..416e7d2
Binary files /dev/null and b/public/emojis/嘿哈.webp differ
diff --git a/public/emojis/噢买尬.webp b/public/emojis/噢买尬.webp
new file mode 100644
index 0000000..e3ca69d
Binary files /dev/null and b/public/emojis/噢买尬.webp differ
diff --git a/public/emojis/囧.webp b/public/emojis/囧.webp
new file mode 100644
index 0000000..31f6b2b
Binary files /dev/null and b/public/emojis/囧.webp differ
diff --git a/public/emojis/困.webp b/public/emojis/困.webp
new file mode 100644
index 0000000..d5cc02a
Binary files /dev/null and b/public/emojis/困.webp differ
diff --git a/public/emojis/圣诞帽.webp b/public/emojis/圣诞帽.webp
new file mode 100644
index 0000000..8f5d89b
Binary files /dev/null and b/public/emojis/圣诞帽.webp differ
diff --git a/public/emojis/圣诞树.webp b/public/emojis/圣诞树.webp
new file mode 100644
index 0000000..afb2266
Binary files /dev/null and b/public/emojis/圣诞树.webp differ
diff --git a/public/emojis/坏笑.webp b/public/emojis/坏笑.webp
new file mode 100644
index 0000000..477290c
Binary files /dev/null and b/public/emojis/坏笑.webp differ
diff --git a/public/emojis/垃圾.webp b/public/emojis/垃圾.webp
new file mode 100644
index 0000000..5fd8898
Binary files /dev/null and b/public/emojis/垃圾.webp differ
diff --git a/public/emojis/大哭.webp b/public/emojis/大哭.webp
new file mode 100644
index 0000000..9bc4d76
Binary files /dev/null and b/public/emojis/大哭.webp differ
diff --git a/public/emojis/大笑.webp b/public/emojis/大笑.webp
new file mode 100644
index 0000000..ec25c4b
Binary files /dev/null and b/public/emojis/大笑.webp differ
diff --git a/public/emojis/大金牙.webp b/public/emojis/大金牙.webp
new file mode 100644
index 0000000..8cdea94
Binary files /dev/null and b/public/emojis/大金牙.webp differ
diff --git a/public/emojis/太阳.webp b/public/emojis/太阳.webp
new file mode 100644
index 0000000..31039f6
Binary files /dev/null and b/public/emojis/太阳.webp differ
diff --git a/public/emojis/奋斗.webp b/public/emojis/奋斗.webp
new file mode 100644
index 0000000..67b87dd
Binary files /dev/null and b/public/emojis/奋斗.webp differ
diff --git a/public/emojis/奸笑.webp b/public/emojis/奸笑.webp
new file mode 100644
index 0000000..6aef417
Binary files /dev/null and b/public/emojis/奸笑.webp differ
diff --git a/public/emojis/好开心.webp b/public/emojis/好开心.webp
new file mode 100644
index 0000000..ec881d0
Binary files /dev/null and b/public/emojis/好开心.webp differ
diff --git a/public/emojis/如花.webp b/public/emojis/如花.webp
new file mode 100644
index 0000000..3cc3892
Binary files /dev/null and b/public/emojis/如花.webp differ
diff --git a/public/emojis/委屈.webp b/public/emojis/委屈.webp
new file mode 100644
index 0000000..843c2a5
Binary files /dev/null and b/public/emojis/委屈.webp differ
diff --git a/public/emojis/宕机.webp b/public/emojis/宕机.webp
new file mode 100644
index 0000000..dd384b9
Binary files /dev/null and b/public/emojis/宕机.webp differ
diff --git a/public/emojis/害羞.webp b/public/emojis/害羞.webp
new file mode 100644
index 0000000..a99ccbd
Binary files /dev/null and b/public/emojis/害羞.webp differ
diff --git a/public/emojis/小鼓掌.webp b/public/emojis/小鼓掌.webp
new file mode 100644
index 0000000..d07ca20
Binary files /dev/null and b/public/emojis/小鼓掌.webp differ
diff --git a/public/emojis/尬笑.webp b/public/emojis/尬笑.webp
new file mode 100644
index 0000000..49110c1
Binary files /dev/null and b/public/emojis/尬笑.webp differ
diff --git a/public/emojis/尴尬流汗.webp b/public/emojis/尴尬流汗.webp
new file mode 100644
index 0000000..bbb6393
Binary files /dev/null and b/public/emojis/尴尬流汗.webp differ
diff --git a/public/emojis/屎.webp b/public/emojis/屎.webp
new file mode 100644
index 0000000..f7b2aaf
Binary files /dev/null and b/public/emojis/屎.webp differ
diff --git a/public/emojis/展开说说.webp b/public/emojis/展开说说.webp
new file mode 100644
index 0000000..c4a9692
Binary files /dev/null and b/public/emojis/展开说说.webp differ
diff --git a/public/emojis/左上.webp b/public/emojis/左上.webp
new file mode 100644
index 0000000..a1dcf15
Binary files /dev/null and b/public/emojis/左上.webp differ
diff --git a/public/emojis/左边.webp b/public/emojis/左边.webp
new file mode 100644
index 0000000..dc6a668
Binary files /dev/null and b/public/emojis/左边.webp differ
diff --git a/public/emojis/巧克力.webp b/public/emojis/巧克力.webp
new file mode 100644
index 0000000..a6de244
Binary files /dev/null and b/public/emojis/巧克力.webp differ
diff --git a/public/emojis/干饭人.webp b/public/emojis/干饭人.webp
new file mode 100644
index 0000000..0a83b48
Binary files /dev/null and b/public/emojis/干饭人.webp differ
diff --git a/public/emojis/平安果.webp b/public/emojis/平安果.webp
new file mode 100644
index 0000000..21f0652
Binary files /dev/null and b/public/emojis/平安果.webp differ
diff --git a/public/emojis/庆祝.webp b/public/emojis/庆祝.webp
new file mode 100644
index 0000000..365d59d
Binary files /dev/null and b/public/emojis/庆祝.webp differ
diff --git a/public/emojis/弱.webp b/public/emojis/弱.webp
new file mode 100644
index 0000000..2e524c7
Binary files /dev/null and b/public/emojis/弱.webp differ
diff --git a/public/emojis/强.webp b/public/emojis/强.webp
new file mode 100644
index 0000000..8606292
Binary files /dev/null and b/public/emojis/强.webp differ
diff --git a/public/emojis/强壮.webp b/public/emojis/强壮.webp
new file mode 100644
index 0000000..972335e
Binary files /dev/null and b/public/emojis/强壮.webp differ
diff --git a/public/emojis/得意.webp b/public/emojis/得意.webp
new file mode 100644
index 0000000..2f77a52
Binary files /dev/null and b/public/emojis/得意.webp differ
diff --git a/public/emojis/微笑.webp b/public/emojis/微笑.webp
new file mode 100644
index 0000000..d0323f4
Binary files /dev/null and b/public/emojis/微笑.webp differ
diff --git a/public/emojis/心碎.webp b/public/emojis/心碎.webp
new file mode 100644
index 0000000..27d1925
Binary files /dev/null and b/public/emojis/心碎.webp differ
diff --git a/public/emojis/快哭了.webp b/public/emojis/快哭了.webp
new file mode 100644
index 0000000..1dc8fae
Binary files /dev/null and b/public/emojis/快哭了.webp differ
diff --git a/public/emojis/思考.webp b/public/emojis/思考.webp
new file mode 100644
index 0000000..fc7ad45
Binary files /dev/null and b/public/emojis/思考.webp differ
diff --git a/public/emojis/恐惧.webp b/public/emojis/恐惧.webp
new file mode 100644
index 0000000..0b6a27c
Binary files /dev/null and b/public/emojis/恐惧.webp differ
diff --git a/public/emojis/悠闲.webp b/public/emojis/悠闲.webp
new file mode 100644
index 0000000..71f2d08
Binary files /dev/null and b/public/emojis/悠闲.webp differ
diff --git a/public/emojis/惊喜.webp b/public/emojis/惊喜.webp
new file mode 100644
index 0000000..2417a17
Binary files /dev/null and b/public/emojis/惊喜.webp differ
diff --git a/public/emojis/惊恐.webp b/public/emojis/惊恐.webp
new file mode 100644
index 0000000..8393a4a
Binary files /dev/null and b/public/emojis/惊恐.webp differ
diff --git a/public/emojis/愉快.webp b/public/emojis/愉快.webp
new file mode 100644
index 0000000..dbc35b5
Binary files /dev/null and b/public/emojis/愉快.webp differ
diff --git a/public/emojis/感谢.webp b/public/emojis/感谢.webp
new file mode 100644
index 0000000..d11725c
Binary files /dev/null and b/public/emojis/感谢.webp differ
diff --git a/public/emojis/愤怒.webp b/public/emojis/愤怒.webp
new file mode 100644
index 0000000..ed21ae3
Binary files /dev/null and b/public/emojis/愤怒.webp differ
diff --git a/public/emojis/憨笑.webp b/public/emojis/憨笑.webp
new file mode 100644
index 0000000..f74f5ab
Binary files /dev/null and b/public/emojis/憨笑.webp differ
diff --git a/public/emojis/懵.webp b/public/emojis/懵.webp
new file mode 100644
index 0000000..5f1344d
Binary files /dev/null and b/public/emojis/懵.webp differ
diff --git a/public/emojis/我想静静.webp b/public/emojis/我想静静.webp
new file mode 100644
index 0000000..097ac6d
Binary files /dev/null and b/public/emojis/我想静静.webp differ
diff --git a/public/emojis/戒指.webp b/public/emojis/戒指.webp
new file mode 100644
index 0000000..77f866f
Binary files /dev/null and b/public/emojis/戒指.webp differ
diff --git a/public/emojis/戳手手.webp b/public/emojis/戳手手.webp
new file mode 100644
index 0000000..30a2c87
Binary files /dev/null and b/public/emojis/戳手手.webp differ
diff --git a/public/emojis/扎心.webp b/public/emojis/扎心.webp
new file mode 100644
index 0000000..a2a1625
Binary files /dev/null and b/public/emojis/扎心.webp differ
diff --git a/public/emojis/打call.webp b/public/emojis/打call.webp
new file mode 100644
index 0000000..9526608
Binary files /dev/null and b/public/emojis/打call.webp differ
diff --git a/public/emojis/打脸.webp b/public/emojis/打脸.webp
new file mode 100644
index 0000000..0dd046e
Binary files /dev/null and b/public/emojis/打脸.webp differ
diff --git a/public/emojis/抓狂.webp b/public/emojis/抓狂.webp
new file mode 100644
index 0000000..ad03544
Binary files /dev/null and b/public/emojis/抓狂.webp differ
diff --git a/public/emojis/抠鼻.webp b/public/emojis/抠鼻.webp
new file mode 100644
index 0000000..d4699ba
Binary files /dev/null and b/public/emojis/抠鼻.webp differ
diff --git a/public/emojis/抱抱你.webp b/public/emojis/抱抱你.webp
new file mode 100644
index 0000000..88bf799
Binary files /dev/null and b/public/emojis/抱抱你.webp differ
diff --git a/public/emojis/抱拳.webp b/public/emojis/抱拳.webp
new file mode 100644
index 0000000..7161a84
Binary files /dev/null and b/public/emojis/抱拳.webp differ
diff --git a/public/emojis/抱紧自己.webp b/public/emojis/抱紧自己.webp
new file mode 100644
index 0000000..93e2e7d
Binary files /dev/null and b/public/emojis/抱紧自己.webp differ
diff --git a/public/emojis/拜拜.webp b/public/emojis/拜拜.webp
new file mode 100644
index 0000000..b4e0456
Binary files /dev/null and b/public/emojis/拜拜.webp differ
diff --git a/public/emojis/拳头.webp b/public/emojis/拳头.webp
new file mode 100644
index 0000000..224e941
Binary files /dev/null and b/public/emojis/拳头.webp differ
diff --git a/public/emojis/捂脸.webp b/public/emojis/捂脸.webp
new file mode 100644
index 0000000..0b46f13
Binary files /dev/null and b/public/emojis/捂脸.webp differ
diff --git a/public/emojis/握手.webp b/public/emojis/握手.webp
new file mode 100644
index 0000000..b6cba2d
Binary files /dev/null and b/public/emojis/握手.webp differ
diff --git a/public/emojis/握爪.webp b/public/emojis/握爪.webp
new file mode 100644
index 0000000..6cad391
Binary files /dev/null and b/public/emojis/握爪.webp differ
diff --git a/public/emojis/摊手.webp b/public/emojis/摊手.webp
new file mode 100644
index 0000000..fe57f65
Binary files /dev/null and b/public/emojis/摊手.webp differ
diff --git a/public/emojis/摸头.webp b/public/emojis/摸头.webp
new file mode 100644
index 0000000..14d7e34
Binary files /dev/null and b/public/emojis/摸头.webp differ
diff --git a/public/emojis/撇嘴.webp b/public/emojis/撇嘴.webp
new file mode 100644
index 0000000..a3649ac
Binary files /dev/null and b/public/emojis/撇嘴.webp differ
diff --git a/public/emojis/撒花.webp b/public/emojis/撒花.webp
new file mode 100644
index 0000000..b97ffac
Binary files /dev/null and b/public/emojis/撒花.webp differ
diff --git a/public/emojis/擦汗.webp b/public/emojis/擦汗.webp
new file mode 100644
index 0000000..92ad876
Binary files /dev/null and b/public/emojis/擦汗.webp differ
diff --git a/public/emojis/敢怒不敢言.webp b/public/emojis/敢怒不敢言.webp
new file mode 100644
index 0000000..dbbd8a0
Binary files /dev/null and b/public/emojis/敢怒不敢言.webp differ
diff --git a/public/emojis/敲打.webp b/public/emojis/敲打.webp
new file mode 100644
index 0000000..beae052
Binary files /dev/null and b/public/emojis/敲打.webp differ
diff --git a/public/emojis/斜眼.webp b/public/emojis/斜眼.webp
new file mode 100644
index 0000000..f85606e
Binary files /dev/null and b/public/emojis/斜眼.webp differ
diff --git a/public/emojis/无语流汗.webp b/public/emojis/无语流汗.webp
new file mode 100644
index 0000000..8f76aaf
Binary files /dev/null and b/public/emojis/无语流汗.webp differ
diff --git a/public/emojis/星星眼.webp b/public/emojis/星星眼.webp
new file mode 100644
index 0000000..2de43d9
Binary files /dev/null and b/public/emojis/星星眼.webp differ
diff --git a/public/emojis/晕.webp b/public/emojis/晕.webp
new file mode 100644
index 0000000..d815e83
Binary files /dev/null and b/public/emojis/晕.webp differ
diff --git a/public/emojis/暗中观察.webp b/public/emojis/暗中观察.webp
new file mode 100644
index 0000000..76ab6b9
Binary files /dev/null and b/public/emojis/暗中观察.webp differ
diff --git a/public/emojis/月亮.webp b/public/emojis/月亮.webp
new file mode 100644
index 0000000..4a1af7e
Binary files /dev/null and b/public/emojis/月亮.webp differ
diff --git a/public/emojis/机智.webp b/public/emojis/机智.webp
new file mode 100644
index 0000000..fbdd0ce
Binary files /dev/null and b/public/emojis/机智.webp differ
diff --git a/public/emojis/杀马特.webp b/public/emojis/杀马特.webp
new file mode 100644
index 0000000..724e68b
Binary files /dev/null and b/public/emojis/杀马特.webp differ
diff --git a/public/emojis/来看我.webp b/public/emojis/来看我.webp
new file mode 100644
index 0000000..9a7251a
Binary files /dev/null and b/public/emojis/来看我.webp differ
diff --git a/public/emojis/柴犬.webp b/public/emojis/柴犬.webp
new file mode 100644
index 0000000..9490435
Binary files /dev/null and b/public/emojis/柴犬.webp differ
diff --git a/public/emojis/栓Q.webp b/public/emojis/栓Q.webp
new file mode 100644
index 0000000..662eaab
Binary files /dev/null and b/public/emojis/栓Q.webp differ
diff --git a/public/emojis/棒棒糖.webp b/public/emojis/棒棒糖.webp
new file mode 100644
index 0000000..433fa38
Binary files /dev/null and b/public/emojis/棒棒糖.webp differ
diff --git a/public/emojis/比心.webp b/public/emojis/比心.webp
new file mode 100644
index 0000000..61e82cb
Binary files /dev/null and b/public/emojis/比心.webp differ
diff --git a/public/emojis/气球.webp b/public/emojis/气球.webp
new file mode 100644
index 0000000..07bb8fc
Binary files /dev/null and b/public/emojis/气球.webp differ
diff --git a/public/emojis/求抱抱.webp b/public/emojis/求抱抱.webp
new file mode 100644
index 0000000..2e05079
Binary files /dev/null and b/public/emojis/求抱抱.webp differ
diff --git a/public/emojis/求机位-黄脸.webp b/public/emojis/求机位-黄脸.webp
new file mode 100644
index 0000000..ae3c6aa
Binary files /dev/null and b/public/emojis/求机位-黄脸.webp differ
diff --git a/public/emojis/求机位3.webp b/public/emojis/求机位3.webp
new file mode 100644
index 0000000..bdc8c3e
Binary files /dev/null and b/public/emojis/求机位3.webp differ
diff --git a/public/emojis/求求了.webp b/public/emojis/求求了.webp
new file mode 100644
index 0000000..fdac652
Binary files /dev/null and b/public/emojis/求求了.webp differ
diff --git a/public/emojis/泣不成声.webp b/public/emojis/泣不成声.webp
new file mode 100644
index 0000000..4f7fb53
Binary files /dev/null and b/public/emojis/泣不成声.webp differ
diff --git a/public/emojis/泪奔.webp b/public/emojis/泪奔.webp
new file mode 100644
index 0000000..24cdca2
Binary files /dev/null and b/public/emojis/泪奔.webp differ
diff --git a/public/emojis/流泪.webp b/public/emojis/流泪.webp
new file mode 100644
index 0000000..edebae1
Binary files /dev/null and b/public/emojis/流泪.webp differ
diff --git a/public/emojis/灯笼.webp b/public/emojis/灯笼.webp
new file mode 100644
index 0000000..832964c
Binary files /dev/null and b/public/emojis/灯笼.webp differ
diff --git a/public/emojis/灵机一动.webp b/public/emojis/灵机一动.webp
new file mode 100644
index 0000000..179b985
Binary files /dev/null and b/public/emojis/灵机一动.webp differ
diff --git a/public/emojis/炸弹.webp b/public/emojis/炸弹.webp
new file mode 100644
index 0000000..51cc5aa
Binary files /dev/null and b/public/emojis/炸弹.webp differ
diff --git a/public/emojis/点火.webp b/public/emojis/点火.webp
new file mode 100644
index 0000000..bd7cb6f
Binary files /dev/null and b/public/emojis/点火.webp differ
diff --git a/public/emojis/点赞.webp b/public/emojis/点赞.webp
new file mode 100644
index 0000000..9c2165e
Binary files /dev/null and b/public/emojis/点赞.webp differ
diff --git a/public/emojis/烟花.webp b/public/emojis/烟花.webp
new file mode 100644
index 0000000..6eb8f3a
Binary files /dev/null and b/public/emojis/烟花.webp differ
diff --git a/public/emojis/热化了.webp b/public/emojis/热化了.webp
new file mode 100644
index 0000000..6d2f7cf
Binary files /dev/null and b/public/emojis/热化了.webp differ
diff --git a/public/emojis/爱心.webp b/public/emojis/爱心.webp
new file mode 100644
index 0000000..c33cec8
Binary files /dev/null and b/public/emojis/爱心.webp differ
diff --git a/public/emojis/爱心手.webp b/public/emojis/爱心手.webp
new file mode 100644
index 0000000..23da451
Binary files /dev/null and b/public/emojis/爱心手.webp differ
diff --git a/public/emojis/猪头.webp b/public/emojis/猪头.webp
new file mode 100644
index 0000000..4762258
Binary files /dev/null and b/public/emojis/猪头.webp differ
diff --git a/public/emojis/玫瑰.webp b/public/emojis/玫瑰.webp
new file mode 100644
index 0000000..74f5fac
Binary files /dev/null and b/public/emojis/玫瑰.webp differ
diff --git a/public/emojis/疑问.webp b/public/emojis/疑问.webp
new file mode 100644
index 0000000..ff69dea
Binary files /dev/null and b/public/emojis/疑问.webp differ
diff --git a/public/emojis/白眼.webp b/public/emojis/白眼.webp
new file mode 100644
index 0000000..9f82398
Binary files /dev/null and b/public/emojis/白眼.webp differ
diff --git a/public/emojis/皱眉.webp b/public/emojis/皱眉.webp
new file mode 100644
index 0000000..99598e4
Binary files /dev/null and b/public/emojis/皱眉.webp differ
diff --git a/public/emojis/看.webp b/public/emojis/看.webp
new file mode 100644
index 0000000..b2882dd
Binary files /dev/null and b/public/emojis/看.webp differ
diff --git a/public/emojis/眼含热泪.webp b/public/emojis/眼含热泪.webp
new file mode 100644
index 0000000..db74ef0
Binary files /dev/null and b/public/emojis/眼含热泪.webp differ
diff --git a/public/emojis/石化.webp b/public/emojis/石化.webp
new file mode 100644
index 0000000..03a0ba8
Binary files /dev/null and b/public/emojis/石化.webp differ
diff --git a/public/emojis/碰拳.webp b/public/emojis/碰拳.webp
new file mode 100644
index 0000000..31b2caa
Binary files /dev/null and b/public/emojis/碰拳.webp differ
diff --git a/public/emojis/礼物.webp b/public/emojis/礼物.webp
new file mode 100644
index 0000000..8a32878
Binary files /dev/null and b/public/emojis/礼物.webp differ
diff --git a/public/emojis/福.webp b/public/emojis/福.webp
new file mode 100644
index 0000000..10a1652
Binary files /dev/null and b/public/emojis/福.webp differ
diff --git a/public/emojis/笑哭.webp b/public/emojis/笑哭.webp
new file mode 100644
index 0000000..bfb9ce2
Binary files /dev/null and b/public/emojis/笑哭.webp differ
diff --git a/public/emojis/粽子.webp b/public/emojis/粽子.webp
new file mode 100644
index 0000000..0a9c76f
Binary files /dev/null and b/public/emojis/粽子.webp differ
diff --git a/public/emojis/精选.webp b/public/emojis/精选.webp
new file mode 100644
index 0000000..a85376d
Binary files /dev/null and b/public/emojis/精选.webp differ
diff --git a/public/emojis/糖葫芦.webp b/public/emojis/糖葫芦.webp
new file mode 100644
index 0000000..ea6852d
Binary files /dev/null and b/public/emojis/糖葫芦.webp differ
diff --git a/public/emojis/紫薇别走.webp b/public/emojis/紫薇别走.webp
new file mode 100644
index 0000000..6c9fdd2
Binary files /dev/null and b/public/emojis/紫薇别走.webp differ
diff --git a/public/emojis/红包.webp b/public/emojis/红包.webp
new file mode 100644
index 0000000..13b46f4
Binary files /dev/null and b/public/emojis/红包.webp differ
diff --git a/public/emojis/红脸.webp b/public/emojis/红脸.webp
new file mode 100644
index 0000000..8529a78
Binary files /dev/null and b/public/emojis/红脸.webp differ
diff --git a/public/emojis/纸飞机.webp b/public/emojis/纸飞机.webp
new file mode 100644
index 0000000..75aabcc
Binary files /dev/null and b/public/emojis/纸飞机.webp differ
diff --git a/public/emojis/给力.webp b/public/emojis/给力.webp
new file mode 100644
index 0000000..e7b5fdd
Binary files /dev/null and b/public/emojis/给力.webp differ
diff --git a/public/emojis/给跪了.webp b/public/emojis/给跪了.webp
new file mode 100644
index 0000000..81dd92a
Binary files /dev/null and b/public/emojis/给跪了.webp differ
diff --git a/public/emojis/绝.webp b/public/emojis/绝.webp
new file mode 100644
index 0000000..a1b65d5
Binary files /dev/null and b/public/emojis/绝.webp differ
diff --git a/public/emojis/绝望的凝视.webp b/public/emojis/绝望的凝视.webp
new file mode 100644
index 0000000..623b4fe
Binary files /dev/null and b/public/emojis/绝望的凝视.webp differ
diff --git a/public/emojis/续火花吧.webp b/public/emojis/续火花吧.webp
new file mode 100644
index 0000000..f2602a0
Binary files /dev/null and b/public/emojis/续火花吧.webp differ
diff --git a/public/emojis/绿帽子.webp b/public/emojis/绿帽子.webp
new file mode 100644
index 0000000..212b283
Binary files /dev/null and b/public/emojis/绿帽子.webp differ
diff --git a/public/emojis/翻白眼.webp b/public/emojis/翻白眼.webp
new file mode 100644
index 0000000..1b5cfb2
Binary files /dev/null and b/public/emojis/翻白眼.webp differ
diff --git a/public/emojis/耶.webp b/public/emojis/耶.webp
new file mode 100644
index 0000000..013ae7a
Binary files /dev/null and b/public/emojis/耶.webp differ
diff --git a/public/emojis/胜利.webp b/public/emojis/胜利.webp
new file mode 100644
index 0000000..5e9fefe
Binary files /dev/null and b/public/emojis/胜利.webp differ
diff --git a/public/emojis/胡瓜.webp b/public/emojis/胡瓜.webp
new file mode 100644
index 0000000..64211c2
Binary files /dev/null and b/public/emojis/胡瓜.webp differ
diff --git a/public/emojis/舔屏.webp b/public/emojis/舔屏.webp
new file mode 100644
index 0000000..a90e430
Binary files /dev/null and b/public/emojis/舔屏.webp differ
diff --git a/public/emojis/色.webp b/public/emojis/色.webp
new file mode 100644
index 0000000..d64ac66
Binary files /dev/null and b/public/emojis/色.webp differ
diff --git a/public/emojis/苦涩.webp b/public/emojis/苦涩.webp
new file mode 100644
index 0000000..2f64cd2
Binary files /dev/null and b/public/emojis/苦涩.webp differ
diff --git a/public/emojis/菜狗.webp b/public/emojis/菜狗.webp
new file mode 100644
index 0000000..b1021e4
Binary files /dev/null and b/public/emojis/菜狗.webp differ
diff --git a/public/emojis/蕉绿.webp b/public/emojis/蕉绿.webp
new file mode 100644
index 0000000..719e690
Binary files /dev/null and b/public/emojis/蕉绿.webp differ
diff --git a/public/emojis/蛋糕.webp b/public/emojis/蛋糕.webp
new file mode 100644
index 0000000..853bb33
Binary files /dev/null and b/public/emojis/蛋糕.webp differ
diff --git a/public/emojis/蜜蜂狗.webp b/public/emojis/蜜蜂狗.webp
new file mode 100644
index 0000000..fdfc508
Binary files /dev/null and b/public/emojis/蜜蜂狗.webp differ
diff --git a/public/emojis/衰.webp b/public/emojis/衰.webp
new file mode 100644
index 0000000..e7d14a8
Binary files /dev/null and b/public/emojis/衰.webp differ
diff --git a/public/emojis/裂开.webp b/public/emojis/裂开.webp
new file mode 100644
index 0000000..1fb60b8
Binary files /dev/null and b/public/emojis/裂开.webp differ
diff --git a/public/emojis/西瓜.webp b/public/emojis/西瓜.webp
new file mode 100644
index 0000000..a569823
Binary files /dev/null and b/public/emojis/西瓜.webp differ
diff --git a/public/emojis/调皮.webp b/public/emojis/调皮.webp
new file mode 100644
index 0000000..387c5d9
Binary files /dev/null and b/public/emojis/调皮.webp differ
diff --git a/public/emojis/贴贴.webp b/public/emojis/贴贴.webp
new file mode 100644
index 0000000..dfc2e56
Binary files /dev/null and b/public/emojis/贴贴.webp differ
diff --git a/public/emojis/赞.webp b/public/emojis/赞.webp
new file mode 100644
index 0000000..bfa54a6
Binary files /dev/null and b/public/emojis/赞.webp differ
diff --git a/public/emojis/躺平.webp b/public/emojis/躺平.webp
new file mode 100644
index 0000000..c516d46
Binary files /dev/null and b/public/emojis/躺平.webp differ
diff --git a/public/emojis/送心.webp b/public/emojis/送心.webp
new file mode 100644
index 0000000..cbbcf84
Binary files /dev/null and b/public/emojis/送心.webp differ
diff --git a/public/emojis/送花.webp b/public/emojis/送花.webp
new file mode 100644
index 0000000..e21e252
Binary files /dev/null and b/public/emojis/送花.webp differ
diff --git a/public/emojis/逞强落泪.webp b/public/emojis/逞强落泪.webp
new file mode 100644
index 0000000..dba810a
Binary files /dev/null and b/public/emojis/逞强落泪.webp differ
diff --git a/public/emojis/鄙视.webp b/public/emojis/鄙视.webp
new file mode 100644
index 0000000..68419ea
Binary files /dev/null and b/public/emojis/鄙视.webp differ
diff --git a/public/emojis/酷拽.webp b/public/emojis/酷拽.webp
new file mode 100644
index 0000000..5710706
Binary files /dev/null and b/public/emojis/酷拽.webp differ
diff --git a/public/emojis/钱.webp b/public/emojis/钱.webp
new file mode 100644
index 0000000..dfa03e6
Binary files /dev/null and b/public/emojis/钱.webp differ
diff --git a/public/emojis/锦鲤.webp b/public/emojis/锦鲤.webp
new file mode 100644
index 0000000..3f56c1d
Binary files /dev/null and b/public/emojis/锦鲤.webp differ
diff --git a/public/emojis/闭嘴.webp b/public/emojis/闭嘴.webp
new file mode 100644
index 0000000..e7e46fa
Binary files /dev/null and b/public/emojis/闭嘴.webp differ
diff --git a/public/emojis/阴险.webp b/public/emojis/阴险.webp
new file mode 100644
index 0000000..37c67fe
Binary files /dev/null and b/public/emojis/阴险.webp differ
diff --git a/public/emojis/难过.webp b/public/emojis/难过.webp
new file mode 100644
index 0000000..9f05607
Binary files /dev/null and b/public/emojis/难过.webp differ
diff --git a/public/emojis/雪花.webp b/public/emojis/雪花.webp
new file mode 100644
index 0000000..c218594
Binary files /dev/null and b/public/emojis/雪花.webp differ
diff --git a/public/emojis/震惊.webp b/public/emojis/震惊.webp
new file mode 100644
index 0000000..b8aae7e
Binary files /dev/null and b/public/emojis/震惊.webp differ
diff --git a/public/emojis/鞠躬.webp b/public/emojis/鞠躬.webp
new file mode 100644
index 0000000..c442bc4
Binary files /dev/null and b/public/emojis/鞠躬.webp differ
diff --git a/public/emojis/鞭炮.webp b/public/emojis/鞭炮.webp
new file mode 100644
index 0000000..f106cf2
Binary files /dev/null and b/public/emojis/鞭炮.webp differ
diff --git a/public/emojis/飞吻.webp b/public/emojis/飞吻.webp
new file mode 100644
index 0000000..3ae5ddf
Binary files /dev/null and b/public/emojis/飞吻.webp differ
diff --git a/public/emojis/黄脸干杯.webp b/public/emojis/黄脸干杯.webp
new file mode 100644
index 0000000..2d97b44
Binary files /dev/null and b/public/emojis/黄脸干杯.webp differ
diff --git a/public/emojis/黄脸祈祷.webp b/public/emojis/黄脸祈祷.webp
new file mode 100644
index 0000000..161da01
Binary files /dev/null and b/public/emojis/黄脸祈祷.webp differ
diff --git a/public/emojis/黑脸.webp b/public/emojis/黑脸.webp
new file mode 100644
index 0000000..470faa4
Binary files /dev/null and b/public/emojis/黑脸.webp differ
diff --git a/public/emojis/鼓掌.webp b/public/emojis/鼓掌.webp
new file mode 100644
index 0000000..3dba4a3
Binary files /dev/null and b/public/emojis/鼓掌.webp differ
diff --git a/public/file.svg b/public/file.svg
deleted file mode 100644
index 004145c..0000000
--- a/public/file.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/globe.svg b/public/globe.svg
deleted file mode 100644
index 567f17b..0000000
--- a/public/globe.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/next.svg b/public/next.svg
deleted file mode 100644
index 5174b28..0000000
--- a/public/next.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/vercel.svg b/public/vercel.svg
deleted file mode 100644
index 7705396..0000000
--- a/public/vercel.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/window.svg b/public/window.svg
deleted file mode 100644
index b2b2a44..0000000
--- a/public/window.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file