Initial commit from Create Next App
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import { google } from "googleapis";
|
||||
import fs from "fs";
|
||||
import { prisma } from "../db";
|
||||
import { parseTags } from "../constants";
|
||||
import type { JobItem } from "@prisma/client";
|
||||
|
||||
async function refreshAccessToken(refreshToken: string) {
|
||||
const oauth2Client = new google.auth.OAuth2(
|
||||
process.env.GOOGLE_CLIENT_ID,
|
||||
process.env.GOOGLE_CLIENT_SECRET,
|
||||
);
|
||||
oauth2Client.setCredentials({ refresh_token: refreshToken });
|
||||
const { credentials } = await oauth2Client.refreshAccessToken();
|
||||
return credentials;
|
||||
}
|
||||
|
||||
export async function getYouTubeClient(userId: string) {
|
||||
const connection = await prisma.youTubeConnection.findUnique({
|
||||
where: { userId },
|
||||
});
|
||||
if (!connection) throw new Error("YouTube account not connected");
|
||||
|
||||
const oauth2Client = new google.auth.OAuth2(
|
||||
process.env.GOOGLE_CLIENT_ID,
|
||||
process.env.GOOGLE_CLIENT_SECRET,
|
||||
);
|
||||
|
||||
let accessToken = connection.accessToken;
|
||||
let expiresAt = connection.expiresAt;
|
||||
|
||||
if (new Date() >= expiresAt) {
|
||||
const credentials = await refreshAccessToken(connection.refreshToken);
|
||||
if (!credentials.access_token) {
|
||||
throw new Error("Failed to refresh YouTube access token");
|
||||
}
|
||||
accessToken = credentials.access_token;
|
||||
expiresAt = credentials.expiry_date
|
||||
? new Date(credentials.expiry_date)
|
||||
: new Date(Date.now() + 3600 * 1000);
|
||||
|
||||
await prisma.youTubeConnection.update({
|
||||
where: { userId },
|
||||
data: { accessToken, expiresAt },
|
||||
});
|
||||
}
|
||||
|
||||
oauth2Client.setCredentials({
|
||||
access_token: accessToken,
|
||||
refresh_token: connection.refreshToken,
|
||||
});
|
||||
|
||||
return google.youtube({ version: "v3", auth: oauth2Client });
|
||||
}
|
||||
|
||||
export async function uploadToYouTube(
|
||||
userId: string,
|
||||
videoPath: string,
|
||||
item: JobItem,
|
||||
): Promise<string> {
|
||||
const youtube = await getYouTubeClient(userId);
|
||||
const tags = parseTags(item.tags);
|
||||
|
||||
const privacyStatus =
|
||||
item.privacy === "PUBLIC"
|
||||
? "public"
|
||||
: item.privacy === "PRIVATE"
|
||||
? "private"
|
||||
: "unlisted";
|
||||
|
||||
const response = await youtube.videos.insert({
|
||||
part: ["snippet", "status"],
|
||||
notifySubscribers: item.notifySubscribers,
|
||||
requestBody: {
|
||||
snippet: {
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
tags: tags.length > 0 ? tags : undefined,
|
||||
categoryId: item.categoryId,
|
||||
},
|
||||
status: {
|
||||
privacyStatus,
|
||||
embeddable: item.embeddable,
|
||||
selfDeclaredMadeForKids: item.madeForKids,
|
||||
licenseId: item.creativeCommons ? "creativeCommon" : "youtube",
|
||||
},
|
||||
},
|
||||
media: {
|
||||
body: fs.createReadStream(videoPath),
|
||||
},
|
||||
});
|
||||
|
||||
const videoId = response.data.id;
|
||||
if (!videoId) throw new Error("YouTube upload succeeded but no video ID returned");
|
||||
return videoId;
|
||||
}
|
||||
|
||||
export async function fetchYouTubeChannel(accessToken: string, refreshToken: string) {
|
||||
const oauth2Client = new google.auth.OAuth2(
|
||||
process.env.GOOGLE_CLIENT_ID,
|
||||
process.env.GOOGLE_CLIENT_SECRET,
|
||||
);
|
||||
oauth2Client.setCredentials({ access_token: accessToken, refresh_token: refreshToken });
|
||||
const youtube = google.youtube({ version: "v3", auth: oauth2Client });
|
||||
const response = await youtube.channels.list({ part: ["snippet"], mine: true });
|
||||
const channel = response.data.items?.[0];
|
||||
if (!channel?.id) throw new Error("No YouTube channel found for this account");
|
||||
return {
|
||||
channelId: channel.id,
|
||||
channelTitle: channel.snippet?.title || "Unknown Channel",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user