feat: Add bgutil-ytdlp-pot-provider integration

This commit is contained in:
Peifan Li
2025-12-02 12:56:12 -05:00
parent 1e5884d454
commit 26184ba3c5
3 changed files with 30 additions and 6 deletions

View File

@@ -9,8 +9,15 @@ COPY package*.json ./
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
# Skip Python check for youtube-dl-exec during build
ENV YOUTUBE_DL_SKIP_PYTHON_CHECK=1
RUN apk add --no-cache git
RUN npm ci
# Clone and build bgutil-ytdlp-pot-provider
RUN git clone --single-branch --branch 1.2.2 https://github.com/Brainicism/bgutil-ytdlp-pot-provider.git /app/bgutil-ytdlp-pot-provider
WORKDIR /app/bgutil-ytdlp-pot-provider/server
RUN npm install && npx tsc
WORKDIR /app
COPY . .
RUN npm run build
@@ -27,9 +34,13 @@ RUN apk add --no-cache \
chromium \
ffmpeg \
python3 \
py3-pip && \
py3-pip \
git && \
ln -sf python3 /usr/bin/python
# Install yt-dlp and bgutil-ytdlp-pot-provider
RUN pip3 install yt-dlp bgutil-ytdlp-pot-provider --break-system-packages
# Environment variables
ENV NODE_ENV=production
ENV PORT=5551
@@ -44,6 +55,8 @@ RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
# Copy drizzle migrations
COPY --from=builder /app/drizzle ./drizzle
# Copy bgutil-ytdlp-pot-provider
COPY --from=builder /app/bgutil-ytdlp-pot-provider /app/bgutil-ytdlp-pot-provider
# Create necessary directories
RUN mkdir -p uploads/videos uploads/images data

Submodule backend/bgutil-ytdlp-pot-provider added at 9c3cc1a21d

View File

@@ -7,6 +7,9 @@ import { sanitizeFilename } from "../../utils/helpers";
import * as storageService from "../storageService";
import { Video } from "../storageService";
const YT_DLP_PATH = process.env.YT_DLP_PATH || "yt-dlp";
const PROVIDER_SCRIPT = process.env.BGUTIL_SCRIPT_PATH || path.join(process.cwd(), "bgutil-ytdlp-pot-provider/server/build/generate_once.js");
// Helper function to extract author from XiaoHongShu page when yt-dlp doesn't provide it
async function extractXiaoHongShuAuthor(url: string): Promise<string | null> {
try {
@@ -54,7 +57,8 @@ export class YtDlpDownloader {
noWarnings: true,
skipDownload: true,
playlistEnd: 5, // Limit to 5 results
} as any);
extractorArgs: `youtubepot-bgutilscript:script_path=${PROVIDER_SCRIPT}`,
} as any, { execPath: YT_DLP_PATH } as any);
if (!searchResults || !(searchResults as any).entries) {
return [];
@@ -87,7 +91,8 @@ export class YtDlpDownloader {
noWarnings: true,
preferFreeFormats: true,
// youtubeSkipDashManifest: true, // Specific to YT, might want to keep or make conditional
} as any);
extractorArgs: `youtubepot-bgutilscript:script_path=${PROVIDER_SCRIPT}`,
} as any, { execPath: YT_DLP_PATH } as any);
return {
title: info.title || "Video",
@@ -127,7 +132,8 @@ export class YtDlpDownloader {
playlistEnd: 5,
noWarnings: true,
flatPlaylist: true, // We only need the ID/URL, not full info
} as any);
extractorArgs: `youtubepot-bgutilscript:script_path=${PROVIDER_SCRIPT}`,
} as any, { execPath: YT_DLP_PATH } as any);
// If it's a playlist/channel, 'entries' will contain the videos
if ((result as any).entries && (result as any).entries.length > 0) {
@@ -178,7 +184,8 @@ export class YtDlpDownloader {
dumpSingleJson: true,
noWarnings: true,
preferFreeFormats: true,
} as any);
extractorArgs: `youtubepot-bgutilscript:script_path=${PROVIDER_SCRIPT}`,
} as any, { execPath: YT_DLP_PATH } as any);
console.log("Video info:", {
title: info.title,
@@ -245,8 +252,11 @@ export class YtDlpDownloader {
];
}
// Add PO Token provider args
flags.extractorArgs = `youtubepot-bgutilscript:script_path=${PROVIDER_SCRIPT}`;
// Use exec to capture stdout for progress
const subprocess = youtubedl.exec(videoUrl, flags);
const subprocess = youtubedl.exec(videoUrl, flags, { execPath: YT_DLP_PATH } as any);
if (onStart) {
onStart(() => {