22
33import ffmpeg from "fluent-ffmpeg" ;
44import ytdl from "@distube/ytdl-core" ;
5- import { video_info } from "play-dl" ;
65import { PassThrough , Readable } from "stream" ;
76import path from "path" ;
87import * as fs from "fs" ;
9- import {
10- detectFfmpegCapabilities ,
11- locateFfmpegPath ,
12- sanitizeFilename ,
13- } from "@/lib/serverUtils" ;
8+ import { initializeConf , sanitizeFilename } from "@/lib/serverUtils" ;
9+ import { FormatData , VideoData } from "@/lib/types" ;
10+ import { NextResponse } from "next/server" ;
1411
1512const DIFFERENCE_TOLERANCE = 0.2 ;
1613const PARENT_PATH =
1714 process . env . NODE_ENV === "production" ? "/temp/stroygetter" : "./temp" ;
1815const CLEANUP_INTERVAL =
1916 process . env . NODE_ENV === "production" ? 1000 * 60 * 30 : 1000 * 60 * 2 ;
20-
21- const buildReadableStream = ( stream : PassThrough ) : ReadableStream => {
22- return new ReadableStream ( {
23- start ( controller ) {
24- stream . on ( "data" , ( chunk : Buffer ) => {
25- controller . enqueue ( chunk ) ;
26- } ) ;
27- stream . on ( "end" , ( ) => {
28- controller . close ( ) ;
29- } ) ;
30- } ,
31- } ) ;
17+ let CONF = {
18+ isInitialized : false ,
19+ ffmpegPath : "" ,
20+ hasNvidiaCapabilities : false ,
3221} ;
3322
3423const createTempDir = ( tmp_dir : string ) => {
@@ -155,31 +144,60 @@ export async function GET(request: Request) {
155144 return new Response ( "Missing quality parameter" , { status : 400 } ) ;
156145 }
157146
158- const ffmpegPath = await locateFfmpegPath ( ) ;
147+ if ( CONF . isInitialized === false ) {
148+ CONF = await initializeConf ( CONF ) ;
149+ }
150+
151+ const ffmpegPath = CONF . ffmpegPath ;
159152 if ( ! ffmpegPath ) {
160153 console . error ( "FFmpeg path not found" ) ;
161154 return new Response ( "An error occurred in the server" , { status : 500 } ) ;
162155 } else {
163156 ffmpeg . setFfmpegPath ( ffmpegPath ) ;
164157 }
165158
166- const videoData = await video_info ( url ) ;
159+ const video = await ytdl . getBasicInfo ( url ) ;
160+ const formatMap = new Map ( ) ;
161+ ( video . player_response . streamingData . adaptiveFormats as FormatData [ ] ) . forEach (
162+ ( format : FormatData ) => {
163+ if ( ! formatMap . has ( format . qualityLabel ) ) {
164+ formatMap . set ( format . qualityLabel , format ) ;
165+ }
166+ }
167+ ) ;
167168
168- if ( ! videoData || ! videoData . video_details || ! videoData . format ) {
169+ const videoData : VideoData = {
170+ video_details : {
171+ title : video . videoDetails . title ,
172+ description : video . videoDetails . description || "" ,
173+ duration : video . videoDetails . lengthSeconds ,
174+ thumbnail : video . videoDetails . thumbnails [ 0 ] . url ,
175+ author : video . videoDetails . author . name ,
176+ } ,
177+ format : Array . from ( formatMap . values ( ) ) ,
178+ } ;
179+
180+ //const videoData = await ytdl.getBasicInfo(url);
181+
182+ if ( ! videoData ) {
169183 return new Response ( "An error occurred while fetching video data" , {
170184 status : 500 ,
171185 } ) ;
172186 }
173187
174- const date = videoData . video_details . uploadedAt || new Date ( ) . toISOString ( ) ;
188+ const date =
189+ video . player_response . microformat . playerMicroformatRenderer . publishDate ||
190+ new Date ( ) . toISOString ( ) ;
175191
176192 const metadata = {
177- title : videoData . video_details . title ,
178- artist : videoData . video_details . channel ?. name || "Unknown artist" ,
179- author : videoData . video_details . channel ?. name || "Unknown author" ,
193+ title : videoData . video_details . title || "Unknown title" ,
194+ artist : videoData . video_details . author || "Unknown artist" ,
195+ author : videoData . video_details . author || "Unknown author" ,
180196 year : date . split ( "T" ) [ 0 ] ,
181- genre : videoData . video_details . type || "Unknown genre" ,
182- album : videoData . video_details . title ,
197+ genre : video . videoDetails . keywords
198+ ? video . videoDetails . keywords . join ( ", " )
199+ : "Unknown genre" ,
200+ album : videoData . video_details . title || "Unknown album" ,
183201 } ;
184202
185203 if ( quality === "audio" ) {
@@ -211,7 +229,8 @@ export async function GET(request: Request) {
211229 } )
212230 . pipe ( audioPassThrough , { end : true } ) ;
213231
214- return new Response ( buildReadableStream ( audioPassThrough ) , {
232+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
233+ return new NextResponse ( audioPassThrough as any , {
215234 headers : {
216235 "Content-Type" : "audio/mpeg" ,
217236 "Content-Disposition" : `attachment; filename="${ encodeURIComponent (
@@ -235,7 +254,7 @@ export async function GET(request: Request) {
235254 TEMP_DIR ,
236255 `merged_${ SANITIZED_TITLE } _${ quality } _${ Date . now ( ) } .mp4`
237256 ) ;
238- const HAS_NVIDIA_GPU = await detectFfmpegCapabilities ( ) ;
257+ const HAS_NVIDIA_GPU = CONF . hasNvidiaCapabilities ;
239258
240259 try {
241260 createTempDir ( TEMP_DIR ) ;
@@ -260,11 +279,14 @@ export async function GET(request: Request) {
260279 ) ;
261280
262281 const fileStream = fs . createReadStream ( MERGED_FILE_PATH ) ;
263- //@ts -expect-error - L'argument de type readstream n'est pas attribuable au paramètre de type Passthrought.
264- return new Response ( buildReadableStream ( fileStream ) , {
282+
283+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
284+ return new NextResponse ( fileStream as any , {
265285 headers : {
266- "Content-Type" : "video/mp4" ,
267- "Content-Disposition" : `attachment; filename="output.mp4"` ,
286+ "Content-Type" : quality === "audio" ? "audio/mpeg" : "video/mp4" ,
287+ "Content-Disposition" : `attachment; filename="${ encodeURIComponent (
288+ metadata . title || "video"
289+ ) . replace ( / [ \u0300 - \u036f ] / g, "" ) } .mp4"`,
268290 } ,
269291 } ) ;
270292 } catch ( error ) {
0 commit comments