@@ -3,8 +3,9 @@ import { TwitchStream, MediaSource } from '../types/index.js';
33import config from "../config.js" ;
44import logger from '../utils/logger.js' ;
55import { Youtube } from '../utils/youtube.js' ;
6- import { downloadToTempFile } from '../utils/yt-dlp.js' ;
6+ import ytdl , { downloadToTempFile } from '../utils/yt-dlp.js' ;
77import { GeneralUtils } from '../utils/shared.js' ;
8+ import { YTResponse } from '../types/index.js' ;
89import path from 'path' ;
910
1011export class MediaService {
@@ -118,7 +119,48 @@ export class MediaService {
118119 } ;
119120 }
120121
121- private _resolveDirectUrlSource ( url : string ) : MediaSource {
122+ private async _resolveDirectUrlSource ( url : string ) : Promise < MediaSource > {
123+ // First try to get metadata using yt-dlp
124+ try {
125+ const metadata = await ytdl ( url , {
126+ dumpJson : true ,
127+ skipDownload : true ,
128+ noWarnings : true ,
129+ quiet : true
130+ } ) as YTResponse ;
131+
132+ // If yt-dlp succeeds, use the extracted metadata
133+ if ( metadata && metadata . title ) {
134+ // Get the best available format URL
135+ let streamUrl = url ;
136+ if ( metadata . formats && Array . isArray ( metadata . formats ) && metadata . formats . length > 0 ) {
137+ // Find the format with both audio and video, preferring higher quality
138+ const bestFormat = metadata . formats
139+ . filter ( ( format ) => format . url && format . ext !== 'm3u8' ) // Avoid HLS streams
140+ . sort ( ( a , b ) => {
141+ // Prefer formats with both audio and video
142+ const aScore = ( a . vcodec && a . vcodec !== 'none' ? 1 : 0 ) + ( a . acodec && a . acodec !== 'none' ? 1 : 0 ) + ( a . height || 0 ) / 1000 ;
143+ const bScore = ( b . vcodec && b . vcodec !== 'none' ? 1 : 0 ) + ( b . acodec && b . acodec !== 'none' ? 1 : 0 ) + ( b . height || 0 ) / 1000 ;
144+ return bScore - aScore ;
145+ } ) [ 0 ] ;
146+
147+ if ( bestFormat && bestFormat . url ) {
148+ streamUrl = bestFormat . url ;
149+ }
150+ }
151+
152+ return {
153+ url : streamUrl ,
154+ title : metadata . title ,
155+ type : 'url'
156+ } ;
157+ }
158+ } catch ( error ) {
159+ // yt-dlp failed, log debug info and continue to fallback
160+ logger . debug ( "yt-dlp failed to extract metadata for URL:" , url , error ) ;
161+ }
162+
163+ // Fallback to original URL parsing logic
122164 let title = "Direct URL" ;
123165 try {
124166 const urlObj = new URL ( url ) ;
0 commit comments