From 284c77d6588e05aa022d87b182fc38d241db05ce Mon Sep 17 00:00:00 2001 From: gunshiz Date: Sat, 15 Aug 2026 23:07:46 +0700 Subject: [PATCH] refactor : change lib file path --- app/api/upload/route.ts | 2 +- app/cdn/[id]/route.ts | 2 +- docs/youtube-api-setup-th.md | 137 ----------------------------------- lib/{cdn => }/cdn-images.ts | 0 lib/cdn/cdn-images.test.ts | 2 +- 5 files changed, 3 insertions(+), 140 deletions(-) delete mode 100644 docs/youtube-api-setup-th.md rename lib/{cdn => }/cdn-images.ts (100%) diff --git a/app/api/upload/route.ts b/app/api/upload/route.ts index ba58a03..1d0ae97 100644 --- a/app/api/upload/route.ts +++ b/app/api/upload/route.ts @@ -2,7 +2,7 @@ import { NextResponse } from "next/server"; import { db } from "@/db"; import { cdn } from "@/db/schema"; import { requireDiscordId } from "@/lib/auth/auth"; -import { validateImageUploadFile, cdnUrl } from "@/lib/cdn/cdn-images"; +import { validateImageUploadFile, cdnUrl } from "@/lib/cdn-images"; export async function POST(req: Request) { let discordId: string; diff --git a/app/cdn/[id]/route.ts b/app/cdn/[id]/route.ts index 0552a35..23e7782 100644 --- a/app/cdn/[id]/route.ts +++ b/app/cdn/[id]/route.ts @@ -1,5 +1,5 @@ import { db } from "@/db"; -import { cdnImageResponse } from "@/lib/cdn/cdn-images"; +import { cdnImageResponse } from "@/lib/cdn-images"; export async function GET( _request: Request, diff --git a/docs/youtube-api-setup-th.md b/docs/youtube-api-setup-th.md deleted file mode 100644 index 80d7a49..0000000 --- a/docs/youtube-api-setup-th.md +++ /dev/null @@ -1,137 +0,0 @@ -# คู่มือตั้งค่า YouTube API สำหรับ Erika - -คู่มือนี้ใช้สำหรับเชื่อมช่อง YouTube หนึ่งช่องกับหน้า `/admin/upload` เพื่ออ่านรายการวิดีโอล่าสุด อัปโหลดวิดีโอ ตั้งภาพปก และตั้งเวลาเผยแพร่ - -## 1. สร้าง Google Cloud Project - -1. เข้า [Google Cloud Console](https://console.cloud.google.com/) -2. กดชื่อโปรเจกต์ด้านบน แล้วเลือก **New project** -3. ตั้งชื่อ เช่น `Erika YouTube Uploader` -4. กด **Create** และเลือกโปรเจกต์ที่สร้างใหม่ - -## 2. เปิดใช้ YouTube Data API v3 - -1. เปิด [YouTube Data API v3](https://console.cloud.google.com/apis/library/youtube.googleapis.com) -2. ตรวจสอบว่าเลือกโปรเจกต์ถูกต้อง -3. กด **Enable** - -API นี้ใช้ทั้งอ่านวิดีโอล่าสุดและอัปโหลดวิดีโอ โดยคำขอทุกแบบจะใช้โควตาของโปรเจกต์ ดูรายละเอียดได้ที่ [YouTube Data API Overview](https://developers.google.com/youtube/v3/getting-started) - -## 3. ตั้งค่า OAuth consent screen - -1. ไปที่ **Google Auth Platform** → **Branding** -2. ใส่ชื่อแอป อีเมลซัพพอร์ต และอีเมลติดต่อผู้พัฒนา -3. ไปที่ **Audience** -4. ถ้าใช้ส่วนตัว ให้เลือก **External** และสถานะ **Testing** -5. เพิ่มบัญชี Google ที่เป็นเจ้าของช่อง YouTube ในรายการ **Test users** -6. ไปที่ **Data Access** และเพิ่ม scope: - -```text -https://www.googleapis.com/auth/youtube.upload -``` - -scope นี้อนุญาตให้ Erika จัดการวิดีโอที่อัปโหลดไปยังช่อง ดูรายละเอียด OAuth ของ YouTube ได้ที่ [OAuth 2.0 for Web Server Applications](https://developers.google.com/youtube/v3/guides/auth/server-side-web-apps) - -## 4. สร้าง OAuth Client - -1. ไปที่ **Google Auth Platform** → **Clients** -2. กด **Create client** -3. เลือกชนิด **Web application** -4. ตั้งชื่อ เช่น `Erika Admin` -5. ใน **Authorized redirect URIs** เพิ่ม URL นี้ โดยเปลี่ยนโดเมนให้ตรงกับ `BASE_URL`: - -```text -https://your-domain.com/api/auth/youtube/callback -``` - -ตัวอย่าง production: - -```text -https://erika.sudloh.com/api/auth/youtube/callback -``` - -ถ้าทดสอบในเครื่องและ `BASE_URL=http://localhost:4000` ให้เพิ่ม: - -```text -http://localhost:4000/api/auth/youtube/callback -``` - -6. กด **Create** แล้วคัดลอก **Client ID** และ **Client secret** - -## 5. สร้าง API Key สำหรับรายการวิดีโอล่าสุด - -1. ไปที่ **APIs & Services** → **Credentials** -2. กด **Create credentials** → **API key** -3. เปิด **Edit API key** -4. ใน **API restrictions** เลือก **Restrict key** -5. เลือกเฉพาะ **YouTube Data API v3** แล้วบันทึก - -หา Channel ID ได้จาก YouTube Studio หรือ URL/ข้อมูลขั้นสูงของช่อง - -## 6. เพิ่มค่าในไฟล์ environment - -เพิ่มค่าต่อไปนี้ใน `.env` และ `.env.local` ตามฐานข้อมูล/สภาพแวดล้อมที่ใช้งาน: - -```env -BASE_URL=https://your-domain.com -YOUTUBE_API_KEY=your_api_key -YOUTUBE_CHANNEL_ID=your_channel_id -YOUTUBE_CLIENT_ID=your_oauth_client_id -YOUTUBE_CLIENT_SECRET=your_oauth_client_secret -``` - -อย่าใส่ secret ในตัวแปรที่ขึ้นต้นด้วย `NEXT_PUBLIC_` และอย่า commit ไฟล์ `.env` - -## 7. ขอ Refresh Token - -1. รีสตาร์ตแอปหลังเพิ่ม environment variables -2. ล็อกอินด้วยบัญชี Discord ที่อยู่ใน `ADMIN_DISCORD_IDS` -3. เปิด URL: - -```text -https://your-domain.com/api/auth/youtube -``` - -4. เลือกบัญชี Google ที่เป็นเจ้าของช่อง YouTube -5. อนุญาตสิทธิ์อัปโหลดวิดีโอ -6. หน้า callback จะแสดง `YOUTUBE_REFRESH_TOKEN` -7. คัดลอกไปใส่ `.env` หรือ `.env.local`: - -```env -YOUTUBE_REFRESH_TOKEN=your_refresh_token -``` - -8. รีสตาร์ตแอปอีกครั้ง - -Refresh token เป็นข้อมูลลับ ห้ามส่งให้ผู้อื่นหรือบันทึกลง Git - -## 8. ทดสอบ - -1. เปิด `/admin/upload` -2. ไปแท็บ **Recent videos** และตรวจสอบว่าวิดีโอ YouTube ล่าสุดแสดงขึ้นมา -3. ไปแท็บ **Upload** เลือกไฟล์วิดีโอและรอแถบ Background upload ครบ 100% -4. กรอกชื่อ รายละเอียด และตั้งค่า YouTube -5. กด **Upload to both platforms** หรือเลือกวันเวลาแล้วกด **Schedule both uploads** -6. ตรวจสอบผลในแท็บ **History** - -## แก้ปัญหาที่พบบ่อย - -### `redirect_uri_mismatch` - -ค่า redirect URI ใน Google Cloud ต้องตรงกับ `${BASE_URL}/api/auth/youtube/callback` ทุกตัวอักษร รวม `http/https` โดเมน พอร์ต และ path - -### ไม่ได้รับ Refresh Token - -ลบสิทธิ์แอปเดิมจากบัญชี Google แล้วเปิด `/api/auth/youtube` ใหม่ ระบบของ Erika ส่ง `access_type=offline` และ `prompt=consent` เพื่อขอ refresh token ใหม่ - -### เห็นหน้า “Google hasn’t verified this app” - -ถ้าแอปอยู่ในโหมด Testing ให้เพิ่มบัญชี Google เป็น Test user ก่อน สำหรับแอปสาธารณะอาจต้องผ่านขั้นตอน OAuth verification ของ Google - -### วิดีโอถูกจำกัดเป็น Private - -โปรเจกต์ API ที่ยังไม่ผ่านการตรวจสอบจาก YouTube อาจถูกจำกัดให้อัปโหลดเป็น Private จนกว่าจะผ่าน API audit - -### Quota เต็ม - -ตรวจสอบที่ **Google Cloud Console** → **APIs & Services** → **YouTube Data API v3** → **Quotas** การอัปโหลดวิดีโอใช้โควตาสูงกว่าการอ่านข้อมูลทั่วไป diff --git a/lib/cdn/cdn-images.ts b/lib/cdn-images.ts similarity index 100% rename from lib/cdn/cdn-images.ts rename to lib/cdn-images.ts diff --git a/lib/cdn/cdn-images.test.ts b/lib/cdn/cdn-images.test.ts index c456e33..25571a4 100644 --- a/lib/cdn/cdn-images.test.ts +++ b/lib/cdn/cdn-images.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { validateImageUploadFile } from "./cdn-images"; +import { validateImageUploadFile } from "../cdn-images"; const png = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);