UNPKG

playdl-music-extractor

Version:

PlayDL Music Extractor is a Extractor/Scrapper and Helps Players to fetch data from play-dl or Custom Extractors , as Per reduces extra work and credentials

459 lines (448 loc) 15 kB
const { search, validate, setToken, playlist_info, video_info, deezer, spotify, soundcloud, } = require('play-dl'); const randomUserAgents = require('random-useragent').getRandom; const trackModel = require('./__trackModeler'); const Album = require('./__album'); class playdlEngine { static __cookies = undefined; static __userAgents = undefined; static async __rawExtractor( rawQuery, __trackBlueprint, __scrapperOptions, playdl, queue, ) { if (!(rawQuery && typeof rawQuery === 'string' && rawQuery !== '')) { return undefined; } let __cacheGarbage; let __indexCount = 0; if ( __scrapperOptions?.fetchOptions?.rawCookies && playdlEngine.__cookies !== __scrapperOptions?.fetchOptions?.rawCookies ) { playdlEngine.__cookies ??= __scrapperOptions?.fetchOptions?.rawCookies; await setToken({ youtube: { cookie: playdlEngine.__cookies, }, }); } if ( __scrapperOptions?.fetchOptions?.userAgents && typeof __scrapperOptions?.fetchOptions?.userAgents === 'string' && __scrapperOptions?.fetchOptions?.userAgents?.toLowerCase()?.trim() === 'random' ) { playdlEngine.__userAgents = [ randomUserAgents(), randomUserAgents(), randomUserAgents(), ]; await setToken({ useragent: playdlEngine.__userAgents, }); } else if ( __scrapperOptions?.fetchOptions?.userAgents && Array.isArray(__scrapperOptions?.fetchOptions?.userAgents) && __scrapperOptions?.fetchOptions?.userAgents?.length > 0 ) { playdlEngine.__userAgents = __scrapperOptions?.fetchOptions?.userAgents; await setToken({ useragent: playdlEngine.__userAgents, }); } const validatedResult = await validate(rawQuery)?.catch(() => undefined); let __searchResults = await playdlEngine.#__customSearch( rawQuery, __scrapperOptions, validatedResult, playdl, __trackBlueprint?.orignal_extractor, queue, ); if ( !( __searchResults && Array.isArray(__searchResults) && __searchResults?.length > 0 ) ) { return undefined; } if ( __scrapperOptions?.fetchOptions?.fetchLimit && !Number.isNaN(Number(__scrapperOptions?.fetchOptions?.fetchLimit)) && parseInt(__scrapperOptions?.fetchOptions?.fetchLimit) > 0 && parseInt(__scrapperOptions?.fetchOptions?.fetchLimit) < Infinity && !( (validatedResult?.includes('playlist') || validatedResult?.includes('album')) && Boolean(__scrapperOptions?.fetchOptions?.skipAlbumLimit) ) ) { __searchResults = __searchResults ?.slice(0, parseInt(__scrapperOptions?.fetchOptions?.fetchLimit ?? 1)) ?.filter(Boolean); } queue.add(__searchResults?.length, 'tracksCount'); let garbageResults = ( await __searchResults?.reduce(async (pervStatusData, newStatusData) => { if (!queue || (queue && queue?.stopped)) return [undefined]; const privData = await pervStatusData; __cacheGarbage = await playdlEngine.__trackModelling( newStatusData, { ...__trackBlueprint, Id: ++__indexCount, }, __scrapperOptions, playdl, queue, ); queue.add(__cacheGarbage, 'track'); if (__cacheGarbage && __scrapperOptions?.eventReturn) { playdl.emit( 'track', __trackBlueprint?.orignal_extractor ?? 'youtube', __cacheGarbage?.album ?? undefined, __cacheGarbage, queue, __scrapperOptions?.eventReturn?.metadata, ); queue.emit( 'track', __trackBlueprint?.orignal_extractor ?? 'youtube', __cacheGarbage?.album ?? undefined, __cacheGarbage, __scrapperOptions?.eventReturn?.metadata, ); } if (privData && Array.isArray(privData) && privData?.length > 0) return [...privData, __cacheGarbage]; return [__cacheGarbage]; }, Promise.resolve()) )?.filter(Boolean); if (!queue?.stopped) { queue.add(garbageResults?.length, 'tracksCount'); queue.complete(); playdl.emit( 'tracks', garbageResults, queue?.album, queue, __scrapperOptions?.eventReturn?.metadata, ); queue.emit( 'tracks', garbageResults, queue?.album, __scrapperOptions?.eventReturn?.metadata, ); } garbageResults = []; return garbageResults; } static async #__customSearch( rawQuery, __scrapperOptions, __validate, playdl, extractor = 'arbitary', queue = undefined, ) { if (extractor && extractor?.toLowerCase()?.trim() === 'arbitary') { return { albumId: false, tracks: [ { url: rawQuery, }, ], }; } let __rawResults; let rawTracks; let garbage; let __videoDetails; const __validateResults = []; if (__validate && __validate?.includes('dz')) { __validateResults[0] = 'deezer'; } else if (__validate && __validate?.includes('sp')) { __validateResults[0] = 'spotify'; } else if (__validate && __validate?.includes('so')) { __validateResults[0] = 'soundcloud'; } else if (__validate && __validate?.includes('yt')) { __validateResults[0] = 'youtube'; } __validateResults[1] = __validate ? __validate?.split('_')?.[1] : undefined; switch (__validateResults[0]) { case 'youtube': if ( ['video', 'track'].includes( __validateResults[1]?.toLowerCase()?.trim(), ) ) { __videoDetails = (await video_info(rawQuery))?.video_details; return __videoDetails ? [__videoDetails] : undefined; } __rawResults = await playlist_info(rawQuery, { incomplete: true, }); rawTracks = await __rawResults?.all_videos(); rawTracks = rawTracks && !( (__validate?.includes('playlist') || __validate?.includes('album')) && Boolean(__scrapperOptions?.fetchOptions?.skipAlbumLimit) ) ? rawTracks ?.slice( 0, parseInt(__scrapperOptions?.fetchOptions?.fetchLimit ?? 1), ) ?.filter(Boolean) : rawTracks; garbage = new Album( __rawResults, queue, rawTracks?.length, __scrapperOptions?.eventReturn?.metadata, ); garbage = null; return rawTracks; case 'deezer': __rawResults = await deezer(rawQuery); if (__rawResults && ['playlist', 'album'].includes(__rawResults.type)) { rawTracks = await __rawResults?.all_tracks(); rawTracks = rawTracks && !( (__validate?.includes('playlist') || __validate?.includes('album')) && Boolean(__scrapperOptions?.fetchOptions?.skipAlbumLimit) ) ? rawTracks ?.slice( 0, parseInt(__scrapperOptions?.fetchOptions?.fetchLimit ?? 1), ) ?.filter(Boolean) : rawTracks; let garbage = new Album( __rawResults, queue, rawTracks?.length, __scrapperOptions?.eventReturn?.metadata, ); garbage = null; return rawTracks; } if (__rawResults && ['user'].includes(__rawResults)) return undefined; return [__rawResults]; case 'soundcloud': __rawResults = await soundcloud(rawQuery); if (__rawResults && ['playlist', 'album'].includes(__rawResults.type)) { return await __rawResults?.fetch(); } if (__rawResults && ['user'].includes(__rawResults)) return undefined; rawTracks = rawTracks && !( (__validate?.includes('playlist') || __validate?.includes('album')) && Boolean(__scrapperOptions?.fetchOptions?.skipAlbumLimit) ) ? rawTracks ?.slice( 0, parseInt(__scrapperOptions?.fetchOptions?.fetchLimit ?? 1), ) ?.filter(Boolean) : rawTracks; return [__rawResults]; case 'spotify': __rawResults = await spotify(rawQuery); if (__rawResults && ['playlist', 'album'].includes(__rawResults.type)) { rawTracks = await __rawResults?.all_tracks(); rawTracks = rawTracks && !( (__validate?.includes('playlist') || __validate?.includes('album')) && Boolean(__scrapperOptions?.fetchOptions?.skipAlbumLimit) ) ? rawTracks ?.slice( 0, parseInt(__scrapperOptions?.fetchOptions?.fetchLimit ?? 1), ) ?.filter(Boolean) : rawTracks; let garbage = new Album( __rawResults, queue, rawTracks?.length, __scrapperOptions?.eventReturn?.metadata, ); garbage = null; return rawTracks; } if (__rawResults && ['user'].includes(__rawResults)) return undefined; rawTracks = rawTracks && !( (__validate?.includes('playlist') || __validate?.includes('album')) && Boolean(__scrapperOptions?.fetchOptions?.skipAlbumLimit) ) ? rawTracks ?.slice( 0, parseInt(__scrapperOptions?.fetchOptions?.fetchLimit ?? 1), ) ?.filter(Boolean) : rawTracks; return [__rawResults]; default: __rawResults = await search(rawQuery, { limit: [Infinity, 0].includes( __scrapperOptions?.fetchOptions?.fetchLimit ?? 1, ) || (__scrapperOptions?.fetchOptions?.fetchLimit ?? 1) <= 0 ? 10 : __scrapperOptions?.fetchOptions?.fetchLimit ?? 1, }); rawTracks = rawTracks && !( (__validate?.includes('playlist') || __validate?.includes('album')) && Boolean(__scrapperOptions?.fetchOptions?.skipAlbumLimit) ) ? rawTracks ?.slice( 0, parseInt(__scrapperOptions?.fetchOptions?.fetchLimit ?? 1), ) ?.filter(Boolean) : rawTracks; if ( __rawResults && Array.isArray(__rawResults) && __rawResults?.length > 1 ) { return __rawResults; } if (!__rawResults[0]?.url) return undefined; __videoDetails = await __rawResults?.reduce(async (total, result) => { if (!queue || (queue && queue?.stopped)) return [undefined]; const privaData = await total; const cachedData = await video_info(result?.url); if (privaData && Array.isArray(privaData) && privaData?.length > 0) return [...privaData, cachedData?.video_details]; return [cachedData?.video_details]; }, Promise.resolve); __videoDetails = __videoDetails?.filter(Boolean); return __videoDetails && Array.isArray(__videoDetails) && __videoDetails?.length > 0 ? __videoDetails : __rawResults; } } static async __trackModelling( __rawTrack, __trackBlueprint, __scrapperOptions, playdl, queue, ) { try { if (!queue || (queue && queue?.stopped)) return undefined; await playdl.__customRatelimit(__scrapperOptions?.ratelimit); const Track = new trackModel( { trackId: parseInt(__trackBlueprint?.Id ?? 0) || 0, url: __trackBlueprint?.url ?? __rawTrack?.url, video_Id: __trackBlueprint?.video_Id ?? __rawTrack?.id, title: __trackBlueprint?.title ?? __rawTrack?.title, views: __trackBlueprint?.views ?? __rawTrack?.views, author: __trackBlueprint?.author ?? __rawTrack?.artist?.name ?? __rawTrack?.channel?.name, author_link: __trackBlueprint?.author_link ?? __rawTrack?.artist?.url ?? __rawTrack?.channel?.url, description: __trackBlueprint?.description ?? __rawTrack?.description, custom_extractor: 'play-dl', duration: (__trackBlueprint?.is_live || __rawTrack?.live ? 0 : __trackBlueprint?.duration) ?? (__rawTrack?.durationInSec ?? 0) * 1000, human_duration: __rawTrack?.durationRaw ?? trackModel.humanTimeConversion( (__trackBlueprint?.is_live || __rawTrack?.live ? 0 : __trackBlueprint?.duration) ?? (__rawTrack?.durationInSec ?? 0) * 1000, ), orignal_extractor: __trackBlueprint?.orignal_extractor ?? 'youtube', thumbnail: __trackBlueprint?.thumbnail ?? __rawTrack?.thumbnails?.sort((a, b) => a?.width - b?.width)?.pop() ?.url, channelName: __trackBlueprint?.channel_Name ?? __rawTrack?.channel?.name ?? __trackBlueprint?.author, channelId: __trackBlueprint?.author ?? __rawTrack?.channel?.id, channel_url: __trackBlueprint?.author_link ?? __rawTrack?.channel?.url, likes: __trackBlueprint?.likes ?? __rawTrack?.likes ?? 0, is_live: __trackBlueprint?.is_live ?? __rawTrack?.live ?? false, dislikes: __trackBlueprint?.dislikes ?? __rawTrack?.dislikes ?? 0, metadata: __scrapperOptions?.eventReturn?.metadata, }, __rawTrack, playdl, queue, { userAgents: playdlEngine.__userAgents, }, ); if ( __scrapperOptions?.streamDownload && __rawTrack?.url && !(!queue || (queue && queue?.stopped)) ) { await Track.getStream( __trackBlueprint?.stream, __scrapperOptions?.ignoreInternalError, true, true, ); } if ( __scrapperOptions?.fetchLyrics && __rawTrack?.url && !(!queue || (queue && queue?.stopped)) ) { await Track.getLyrics(); } return Track; } catch (rawError) { if (__scrapperOptions?.ignoreInternalError) { return void playdl.__errorHandling(rawError); } throw rawError; } } } module.exports = playdlEngine;