yt-dlx
Version:
Effortless Audio-Video Downloader And Streamer!
197 lines • 9.65 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = extract;
const path_1 = __importDefault(require("path"));
const colors_1 = __importDefault(require("colors"));
const youtubei_1 = require("youtubei");
const zod_1 = require("zod");
const Agent_1 = __importDefault(require("../../../utils/Agent"));
const youtubei_js_1 = require("youtubei.js");
const ZodSchema = zod_1.z.object({ query: zod_1.z.string().min(2), useTor: zod_1.z.boolean().optional(), verbose: zod_1.z.boolean().optional() });
function calculateUploadAgo(days) {
const years = Math.floor(days / 365);
const months = Math.floor((days % 365) / 30);
const remainingDays = days % 30;
const formattedString = `${years > 0 ? years + " years, " : ""}${months > 0 ? months + " months, " : ""}${remainingDays} days`;
return { years, months, days: remainingDays, formatted: formattedString };
}
function calculateVideoDuration(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
const formattedString = `${hours > 0 ? hours + " hours, " : ""}${minutes > 0 ? minutes + " minutes, " : ""}${remainingSeconds} seconds`;
return { hours, minutes, seconds: remainingSeconds, formatted: formattedString };
}
function formatCount(count) {
const abbreviations = ["K", "M", "B", "T"];
for (let i = abbreviations.length - 1; i >= 0; i--) {
const size = Math.pow(10, (i + 1) * 3);
if (size <= count) {
const formattedCount = Math.round((count / size) * 10) / 10;
return `${formattedCount}${abbreviations[i]}`;
}
}
return `${count}`;
}
async function fetchCommentsByVideoId(videoId, verbose) {
try {
if (verbose)
console.log(colors_1.default.green("@info:"), `Workspaceing comments for video ID: ${videoId}`);
const youtubeInnertube = await youtubei_js_1.Innertube.create({
user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
cache: new youtubei_js_1.UniversalCache(true, path_1.default.join(process.cwd(), "YouTubeDLX")),
});
const response = await youtubeInnertube.getComments(videoId);
const comments = response.contents
.map(thread => {
const comment = thread?.comment;
if (!comment || !comment.content?.text || !comment.published_time || !comment.author?.name)
return null;
return {
comment_id: comment.comment_id || "",
is_pinned: comment.is_pinned || false,
comment: comment.content.text,
published_time: comment.published_time,
author_is_channel_owner: comment.author_is_channel_owner || false,
creator_thumbnail_url: comment.creator_thumbnail_url || "",
like_count: comment.like_count || 0,
is_member: comment.is_member || false,
author: comment.author.name,
is_hearted: comment.is_hearted || false,
is_liked: comment.is_liked || false,
is_disliked: comment.is_disliked || false,
reply_count: comment.reply_count || 0,
hasReplies: thread.has_replies || false,
};
})
.filter((item) => item !== null);
if (comments.length === 0) {
if (verbose)
console.log(colors_1.default.red("@error:"), "No comments found for the video");
return null;
}
if (verbose)
console.log(colors_1.default.green("@info:"), "Video comments fetched!");
return comments;
}
catch (error) {
if (verbose)
console.error(colors_1.default.red("@error: ") + error.message);
return null;
}
}
async function fetchVideoTranscript(videoId, verbose) {
try {
if (verbose)
console.log(colors_1.default.green("@info:"), `Workspaceing transcript for video ID: ${videoId}`);
const youtube = new youtubei_1.Client();
const captions = await youtube.getVideoTranscript(videoId);
if (!captions) {
if (verbose)
console.log(colors_1.default.red("@error:"), "No transcript found for the video");
return null;
}
const transcript = captions.map(caption => ({
text: caption.text,
start: caption.start,
duration: caption.duration,
segments: caption.segments.map(segment => ({ utf8: segment.utf8, tOffsetMs: segment.tOffsetMs, acAsrConf: segment.acAsrConf })),
}));
if (verbose)
console.log(colors_1.default.green("@info:"), "Video transcript fetched!");
return transcript;
}
catch (error) {
if (verbose)
console.error(colors_1.default.red("@error: ") + error.message);
return null;
}
}
async function extract(options) {
try {
const { query, useTor, verbose } = ZodSchema.parse(options);
const metaBody = await (0, Agent_1.default)({ query, verbose, useTor });
if (!metaBody) {
throw new Error(`${colors_1.default.red("@error:")} Unable to get response!`);
}
if (!metaBody.metaData) {
throw new Error(`${colors_1.default.red("@error:")} Metadata not found in the response!`);
}
let uploadDate;
try {
if (metaBody.metaData.upload_date) {
uploadDate = new Date(metaBody.metaData.upload_date.replace(/(\d{4})(\d{2})(\d{2})/, "$1-$2-$3"));
}
}
catch (error) {
throw new Error(`${colors_1.default.red("@error:")} Failed to parse upload date: ${error instanceof Error ? error.message : String(error)}`);
}
const currentDate = new Date();
const daysAgo = uploadDate ? Math.floor((currentDate.getTime() - uploadDate.getTime()) / (1000 * 60 * 60 * 24)) : 0;
const prettyDate = uploadDate?.toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }) || "N/A";
const uploadAgoObject = calculateUploadAgo(daysAgo);
const videoTimeInSeconds = metaBody.metaData.duration;
const videoDuration = calculateVideoDuration(videoTimeInSeconds);
const viewCountFormatted = metaBody.metaData.view_count !== undefined ? formatCount(metaBody.metaData.view_count) : "N/A";
const likeCountFormatted = metaBody.metaData.like_count !== undefined ? formatCount(metaBody.metaData.like_count) : "N/A";
const commentCountFormatted = metaBody.metaData.comment_count !== undefined ? formatCount(metaBody.metaData.comment_count) : "N/A";
const channelFollowerCountFormatted = metaBody.metaData.channel_follower_count !== undefined ? formatCount(metaBody.metaData.channel_follower_count) : "N/A";
const commentsPromise = fetchCommentsByVideoId(metaBody.metaData.id, verbose ?? false);
const transcriptPromise = fetchVideoTranscript(metaBody.metaData.id, verbose ?? false);
const [comments, transcript] = await Promise.all([commentsPromise, transcriptPromise]);
const payload = {
BestAudioLow: metaBody.BestAudioLow,
BestAudioHigh: metaBody.BestAudioHigh,
BestVideoLow: metaBody.BestVideoLow,
BestVideoHigh: metaBody.BestVideoHigh,
AudioLowDRC: metaBody.AudioLowDRC,
AudioHighDRC: metaBody.AudioHighDRC,
AudioLow: metaBody.AudioLow,
AudioHigh: metaBody.AudioHigh,
VideoLowHDR: metaBody.VideoLowHDR,
VideoHighHDR: metaBody.VideoHighHDR,
VideoLow: metaBody.VideoLow,
VideoHigh: metaBody.VideoHigh,
ManifestLow: metaBody.ManifestLow,
ManifestHigh: metaBody.ManifestHigh,
meta_data: {
...metaBody.metaData,
view_count_formatted: viewCountFormatted,
like_count_formatted: likeCountFormatted,
duration: videoDuration.seconds,
upload_date: prettyDate,
upload_ago: daysAgo,
upload_ago_formatted: uploadAgoObject,
comment_count_formatted: commentCountFormatted,
channel_follower_count_formatted: channelFollowerCountFormatted,
},
comments,
transcript,
};
if (verbose)
console.log(colors_1.default.green("@info:"), "❣️ Thank you for using yt-dlx. Consider 🌟starring the GitHub repo https://github.com/yt-dlx.");
return { data: payload };
}
catch (error) {
if (error instanceof zod_1.ZodError) {
const errorMessage = `${colors_1.default.red("@error:")} Argument validation failed: ${error.errors.map(e => `${e.path.join(".")}: ${e.message}`).join(", ")}`;
console.error(errorMessage);
throw new Error(errorMessage);
}
else if (error instanceof Error) {
console.error(error.message);
throw error;
}
else {
const unexpectedError = `${colors_1.default.red("@error:")} An unexpected error occurred: ${String(error)}`;
console.error(unexpectedError);
throw new Error(unexpectedError);
}
}
finally {
}
}
//# sourceMappingURL=Extract.js.map