wow
This commit is contained in:
parent
68bb75b1c8
commit
fa35d5c305
3 changed files with 46 additions and 20 deletions
|
|
@ -18,6 +18,7 @@ type UploadResponse = {
|
||||||
message: string;
|
message: string;
|
||||||
savedCount?: number;
|
savedCount?: number;
|
||||||
failedCount?: number;
|
failedCount?: number;
|
||||||
|
ids?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type ExistsResponse = {
|
type ExistsResponse = {
|
||||||
|
|
@ -120,13 +121,13 @@ async function uploadAndCreateWithRetry(options: {
|
||||||
fileName: string;
|
fileName: string;
|
||||||
mediaUrl: string;
|
mediaUrl: string;
|
||||||
mediaIndex: number;
|
mediaIndex: number;
|
||||||
createDocument: () => Promise<void>;
|
createDocument: () => Promise<any>;
|
||||||
}) {
|
}) {
|
||||||
const { fileName, mediaUrl, mediaIndex, createDocument } = options;
|
const { fileName, mediaUrl, mediaIndex, createDocument } = options;
|
||||||
|
|
||||||
const existingBefore = await MediaUpload.findOne({ s3Key: fileName, mediaIndex });
|
const existingBefore = await MediaUpload.findOne({ s3Key: fileName, mediaIndex });
|
||||||
if (existingBefore) {
|
if (existingBefore) {
|
||||||
return { ok: true as const, created: false };
|
return { ok: true as const, created: false, id: existingBefore._id.toString() };
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastError: unknown;
|
let lastError: unknown;
|
||||||
|
|
@ -138,16 +139,16 @@ async function uploadAndCreateWithRetry(options: {
|
||||||
|
|
||||||
const existing = await MediaUpload.findOne({ s3Key: fileName, mediaIndex });
|
const existing = await MediaUpload.findOne({ s3Key: fileName, mediaIndex });
|
||||||
if (existing) {
|
if (existing) {
|
||||||
return { ok: true as const, created: false };
|
return { ok: true as const, created: false, id: existing._id.toString() };
|
||||||
}
|
}
|
||||||
|
|
||||||
await createDocument();
|
const doc = await createDocument();
|
||||||
return { ok: true as const, created: true };
|
return { ok: true as const, created: true, id: doc._id.toString() };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
lastError = error;
|
lastError = error;
|
||||||
const existingAfterError = await MediaUpload.findOne({ s3Key: fileName, mediaIndex });
|
const existingAfterError = await MediaUpload.findOne({ s3Key: fileName, mediaIndex });
|
||||||
if (existingAfterError) {
|
if (existingAfterError) {
|
||||||
return { ok: true as const, created: false };
|
return { ok: true as const, created: false, id: existingAfterError._id.toString() };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attempt < 2) {
|
if (attempt < 2) {
|
||||||
|
|
@ -397,7 +398,11 @@ export default new Elysia({ prefix: "/post" })
|
||||||
|
|
||||||
const existingPost = await checkExistingPostByUrl(body.url);
|
const existingPost = await checkExistingPostByUrl(body.url);
|
||||||
if (existingPost.exists) {
|
if (existingPost.exists) {
|
||||||
return uploadOk("이미 저장된 게시물입니다.", { savedCount: 0, failedCount: 0 });
|
return uploadOk("이미 저장된 게시물입니다.", {
|
||||||
|
savedCount: 0,
|
||||||
|
failedCount: 0,
|
||||||
|
ids: existingPost.documentId ? [existingPost.documentId] : [],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body.url.startsWith("https://www.pixiv.net/")) {
|
if (body.url.startsWith("https://www.pixiv.net/")) {
|
||||||
|
|
@ -428,6 +433,7 @@ export default new Elysia({ prefix: "/post" })
|
||||||
let failedCount = 0;
|
let failedCount = 0;
|
||||||
const hasExplicitSelection = body.selected.length > 0;
|
const hasExplicitSelection = body.selected.length > 0;
|
||||||
|
|
||||||
|
const savedIds: string[] = [];
|
||||||
for (const [index, mediaUrl] of mediaUrls.entries()) {
|
for (const [index, mediaUrl] of mediaUrls.entries()) {
|
||||||
const isSelected = hasExplicitSelection
|
const isSelected = hasExplicitSelection
|
||||||
? body.selected[index] === true
|
? body.selected[index] === true
|
||||||
|
|
@ -446,7 +452,7 @@ export default new Elysia({ prefix: "/post" })
|
||||||
mediaUrl,
|
mediaUrl,
|
||||||
mediaIndex: index,
|
mediaIndex: index,
|
||||||
createDocument: async () => {
|
createDocument: async () => {
|
||||||
await MediaUpload.create({
|
return await MediaUpload.create({
|
||||||
type: "pixiv",
|
type: "pixiv",
|
||||||
tweet: {
|
tweet: {
|
||||||
id: illustId,
|
id: illustId,
|
||||||
|
|
@ -477,6 +483,10 @@ export default new Elysia({ prefix: "/post" })
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.id) {
|
||||||
|
savedIds.push(result.id);
|
||||||
|
}
|
||||||
|
|
||||||
if (result.created) {
|
if (result.created) {
|
||||||
await saveTags(normalizedTags);
|
await saveTags(normalizedTags);
|
||||||
savedCount += 1;
|
savedCount += 1;
|
||||||
|
|
@ -523,6 +533,7 @@ export default new Elysia({ prefix: "/post" })
|
||||||
return uploadOk("업로드가 완료되었습니다.", {
|
return uploadOk("업로드가 완료되었습니다.", {
|
||||||
savedCount,
|
savedCount,
|
||||||
failedCount,
|
failedCount,
|
||||||
|
ids: savedIds,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[Pixiv upload aborted] requestId=${requestId} key=${uploadKey}`, error);
|
console.error(`[Pixiv upload aborted] requestId=${requestId} key=${uploadKey}`, error);
|
||||||
|
|
@ -551,6 +562,7 @@ export default new Elysia({ prefix: "/post" })
|
||||||
if (media.length > 0) {
|
if (media.length > 0) {
|
||||||
const mediaUrls = media.map((m: any) => m.url);
|
const mediaUrls = media.map((m: any) => m.url);
|
||||||
const hasExplicitSelection = body.selected.length > 0;
|
const hasExplicitSelection = body.selected.length > 0;
|
||||||
|
const savedIds: string[] = [];
|
||||||
for (const [index, url] of mediaUrls.entries()) {
|
for (const [index, url] of mediaUrls.entries()) {
|
||||||
const isSelected = hasExplicitSelection
|
const isSelected = hasExplicitSelection
|
||||||
? body.selected[index] === true
|
? body.selected[index] === true
|
||||||
|
|
@ -569,7 +581,7 @@ export default new Elysia({ prefix: "/post" })
|
||||||
mediaUrl: url,
|
mediaUrl: url,
|
||||||
mediaIndex: index,
|
mediaIndex: index,
|
||||||
createDocument: async () => {
|
createDocument: async () => {
|
||||||
await MediaUpload.create({
|
return await MediaUpload.create({
|
||||||
type: "twitter",
|
type: "twitter",
|
||||||
tweet: tweetWithoutMedia,
|
tweet: tweetWithoutMedia,
|
||||||
mediaIndex: index,
|
mediaIndex: index,
|
||||||
|
|
@ -593,6 +605,10 @@ export default new Elysia({ prefix: "/post" })
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.id) {
|
||||||
|
savedIds.push(result.id);
|
||||||
|
}
|
||||||
|
|
||||||
if (result.created) {
|
if (result.created) {
|
||||||
await saveTags(normalizedTags);
|
await saveTags(normalizedTags);
|
||||||
savedCount += 1;
|
savedCount += 1;
|
||||||
|
|
@ -643,6 +659,7 @@ export default new Elysia({ prefix: "/post" })
|
||||||
return uploadOk("업로드가 완료되었습니다.", {
|
return uploadOk("업로드가 완료되었습니다.", {
|
||||||
savedCount,
|
savedCount,
|
||||||
failedCount,
|
failedCount,
|
||||||
|
ids: savedIds,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[Upload aborted] requestId=${requestId} key=${uploadKey}`, error);
|
console.error(`[Upload aborted] requestId=${requestId} key=${uploadKey}`, error);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import { FormEvent, useEffect, useMemo, useState } from "react";
|
import { FormEvent, useEffect, useMemo, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
import Header from "../../components/header";
|
import Header from "../../components/header";
|
||||||
|
|
||||||
type SourceType = "twitter" | "pixiv";
|
type SourceType = "twitter" | "pixiv";
|
||||||
|
|
@ -32,6 +33,7 @@ type UploadApiResponse = {
|
||||||
message: string;
|
message: string;
|
||||||
savedCount?: number;
|
savedCount?: number;
|
||||||
failedCount?: number;
|
failedCount?: number;
|
||||||
|
ids?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type ExistsApiResponse = {
|
type ExistsApiResponse = {
|
||||||
|
|
@ -63,6 +65,7 @@ function splitTags(text: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AddPage() {
|
export default function AddPage() {
|
||||||
|
const router = useRouter();
|
||||||
const [url, setUrl] = useState("");
|
const [url, setUrl] = useState("");
|
||||||
const [author, setAuthor] = useState("");
|
const [author, setAuthor] = useState("");
|
||||||
const [tagsText, setTagsText] = useState("");
|
const [tagsText, setTagsText] = useState("");
|
||||||
|
|
@ -313,6 +316,10 @@ export default function AddPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
setSuccess(message);
|
setSuccess(message);
|
||||||
|
|
||||||
|
if (data?.ids && data.ids.length > 0) {
|
||||||
|
router.push(`/detail/${data.ids[0]}`);
|
||||||
|
}
|
||||||
} catch (submitError) {
|
} catch (submitError) {
|
||||||
setError(submitError instanceof Error ? submitError.message : "업로드에 실패했습니다.");
|
setError(submitError instanceof Error ? submitError.message : "업로드에 실패했습니다.");
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -214,17 +214,19 @@ export default function App() {
|
||||||
|
|
||||||
async function copyImage(photo: GalleryPhoto) {
|
async function copyImage(photo: GalleryPhoto) {
|
||||||
try {
|
try {
|
||||||
if (typeof ClipboardItem !== "undefined" && navigator.clipboard?.write) {
|
const response = await fetch(photo.src);
|
||||||
const response = await fetch(photo.src, { cache: "no-store" });
|
if (!response.ok) throw new Error("Failed to fetch image");
|
||||||
const blob = await response.blob();
|
|
||||||
await navigator.clipboard.write([new ClipboardItem({ [blob.type || "image/png"]: blob })]);
|
const blob = await response.blob();
|
||||||
} else if (navigator.clipboard?.writeText) {
|
const clipboardItem = new ClipboardItem({
|
||||||
await navigator.clipboard.writeText(photo.src);
|
[blob.type]: blob
|
||||||
}
|
});
|
||||||
} catch {
|
|
||||||
if (navigator.clipboard?.writeText) {
|
await navigator.clipboard.write([clipboardItem]);
|
||||||
await navigator.clipboard.writeText(photo.src);
|
alert("이미지가 클립보드에 복사되었습니다!");
|
||||||
}
|
} catch (error) {
|
||||||
|
console.error("Failed to copy image:", error);
|
||||||
|
alert("이미지 복사에 실패했습니다. 브라우저 호환성 문제일 수 있습니다.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue