ytdl-core
Advanced tools
Comparing version 2.1.5 to 3.0.0
@@ -17,11 +17,5 @@ const PassThrough = require('stream').PassThrough; | ||
const stream = createStream(options); | ||
ytdl.getInfo(link, options, (err, info) => { | ||
if (err) { | ||
stream.emit('error', err); | ||
return; | ||
} | ||
ytdl.getInfo(link, options).then(info => { | ||
downloadFromInfoCallback(stream, info, options); | ||
}); | ||
}, stream.emit.bind(stream, 'error')); | ||
return stream; | ||
@@ -28,0 +22,0 @@ }; |
@@ -44,8 +44,2 @@ const util = require('./util'); | ||
let contents = row.richMetadataRowRenderer.contents; | ||
for (let content of contents) { | ||
let meta = content.richMetadataRenderer; | ||
media.thumbnails = meta.thumbnail.thumbnails; | ||
// TODO: Added for backwards compatibility. Remove later. | ||
media.image = urllib.resolve(VIDEO_URL, media.thumbnails[0].url); | ||
} | ||
let richMeta = contents | ||
@@ -60,2 +54,6 @@ .filter(meta => meta.richMetadataRenderer.style === 'RICH_METADATA_RENDERER_STYLE_BOX_ART'); | ||
meta.endpoint.commandMetadata.webCommandMetadata.url); | ||
media.thumbnails = meta.thumbnail.thumbnails; | ||
// TODO: Added for backwards compatibility. Remove later. | ||
util.deprecate(media, 'image', urllib.resolve(VIDEO_URL, media.thumbnails[0].url), | ||
'info.videoDetails.media.image', 'info.videoDetails.media.thumbnails'); | ||
} | ||
@@ -62,0 +60,0 @@ } |
113
lib/info.js
@@ -38,3 +38,3 @@ const urllib = require('url'); | ||
let [, body] = await miniget.promise(url, reqOptions); | ||
let body = await miniget(url, reqOptions).text(); | ||
let info; | ||
@@ -56,3 +56,3 @@ try { | ||
let embedUrl = `${EMBED_URL + id}?${params}`; | ||
[, body] = await miniget.promise(embedUrl, options.requestOptions); | ||
body = await miniget(embedUrl, options.requestOptions).text(); | ||
let jsonStr = util.between(body, 't.setConfig({\'PLAYER_CONFIG\': ', '</script>'); | ||
@@ -104,25 +104,25 @@ let config; | ||
const gotConfig = async(id, options, info, body) => { | ||
const url = urllib.format({ | ||
protocol: 'https', | ||
host: INFO_HOST, | ||
pathname: INFO_PATH, | ||
query: { | ||
video_id: id, | ||
eurl: VIDEO_EURL + id, | ||
ps: 'default', | ||
gl: 'US', | ||
hl: options.lang || 'en', | ||
sts: info.sts, | ||
}, | ||
}); | ||
let [, morebody] = await miniget.promise(url, options.requestOptions); | ||
let moreinfo = querystring.parse(morebody); | ||
const player_response = | ||
(info.player && info.player.args && info.player.args.player_response) || | ||
moreinfo.player_response || | ||
info.playerResponse; | ||
let player_response = | ||
info.player && info.player.args && info.player.args.player_response; | ||
if (moreinfo.status === 'fail') { | ||
throw Error(`Code ${moreinfo.errorcode}: ${util.stripHTML(moreinfo.reason)}`); | ||
} else if (typeof player_response === 'object') { | ||
if (!player_response) { | ||
const url = urllib.format({ | ||
protocol: 'https', | ||
host: INFO_HOST, | ||
pathname: INFO_PATH, | ||
query: { | ||
video_id: id, | ||
eurl: VIDEO_EURL + id, | ||
ps: 'default', | ||
gl: 'US', | ||
hl: options.lang || 'en', | ||
sts: info.sts, | ||
}, | ||
}); | ||
let morebody = await miniget(url, options.requestOptions).text(); | ||
let moreinfo = querystring.parse(morebody); | ||
player_response = moreinfo.player_response || info.playerResponse; | ||
} | ||
if (typeof player_response === 'object') { | ||
info.player_response = player_response; | ||
@@ -140,40 +140,36 @@ } else { | ||
// Add additional properties to info. | ||
// TODO: Clean up some of these properties that would be better accessed | ||
// directly through `videoDetails`. | ||
let videoDetails = info.player_response.videoDetails; | ||
Object.assign(info, { | ||
// Get the author/uploader. | ||
let additional = { | ||
author: extras.getAuthor(info), | ||
// Get the day the vid was published. | ||
published: Date.parse( | ||
info.player_response.microformat.playerMicroformatRenderer.publishDate, | ||
), | ||
// Get description. | ||
description: videoDetails.shortDescription, | ||
// Get media info. | ||
media: extras.getMedia(body), | ||
// Get related videos. | ||
related_videos: extras.getRelatedVideos(info), | ||
// Get likes. | ||
likes: extras.getLikes(body), | ||
// Get dislikes. | ||
dislikes: extras.getDislikes(body), | ||
age_restricted: !!(info.player.args && info.player.args.is_embed), | ||
video_id: videoDetails.videoId, | ||
// Give the standard link to the video. | ||
video_url: VIDEO_URL + videoDetails.videoId, | ||
video_url: VIDEO_URL + id, | ||
}; | ||
title: videoDetails.title, | ||
length_seconds: videoDetails.lengthSeconds, | ||
info.videoDetails = Object.assign({}, | ||
info.player_response.microformat.playerMicroformatRenderer, | ||
info.player_response.videoDetails, additional); | ||
info.related_videos = extras.getRelatedVideos(info); | ||
info.html5player = info.player && info.player.assets && info.player.assets.js; | ||
age_restricted: !!(info.player.args && info.player.args.is_embed), | ||
html5player: info.player && info.player.assets && info.player.assets.js, | ||
}); | ||
// TODO: Remove these warnings later and remove the properties. | ||
// Remember to remove from typings too. | ||
for (let [prop, value] of Object.entries(additional)) { | ||
util.deprecate(info, prop, value, `info.${prop}`, `info.videoDetails.${prop}`); | ||
} | ||
util.deprecate(info, 'published', info.player_response.microformat.playerMicroformatRenderer.publishDate, | ||
'info.published', 'info.videoDetails.publishDate'); | ||
let props = { | ||
description: 'shortDescription', | ||
video_id: 'videoId', | ||
title: 'title', | ||
length_seconds: 'lengthSeconds', | ||
}; | ||
for (let [oldProp, newProp] of Object.entries(props)) { | ||
util.deprecate(info, oldProp, info.videoDetails[newProp], | ||
`info.${oldProp}`, `info.videoDetails.${newProp}`); | ||
} | ||
@@ -256,3 +252,3 @@ return info; | ||
url = urllib.resolve(VIDEO_URL, url); | ||
let [, body] = await miniget.promise(url, options.requestOptions); | ||
let body = await miniget(url, options.requestOptions).text(); | ||
let formats = {}; | ||
@@ -281,3 +277,3 @@ body | ||
* @param {Function(Error, Object)} callback | ||
* @returns {Object} | ||
* @returns {Promise<Object>} | ||
*/ | ||
@@ -294,2 +290,7 @@ const fn = exports[fnName]; | ||
if (callback) { | ||
// TODO: Fully remove callback support in a future release. | ||
// eslint-disable-next-line no-console | ||
console.warn( | ||
`Calling \`ytdl.${fnName}\` with a callback will be removed in a near future release. ` + | ||
`Use async/await.`); | ||
return exports[fnName](link, options) | ||
@@ -296,0 +297,0 @@ .then(info => callback(null, info), callback); |
@@ -22,3 +22,3 @@ const url = require('url'); | ||
} else { | ||
let [, body] = await miniget.promise(html5playerfile, options.requestOptions); | ||
let body = await miniget(html5playerfile, options.requestOptions).text(); | ||
const tokens = exports.extractActions(body); | ||
@@ -199,5 +199,4 @@ if (!tokens || !tokens.length) { | ||
* @param {string} sig | ||
* @param {boolean} debug | ||
*/ | ||
exports.setDownloadURL = (format, sig, debug) => { | ||
exports.setDownloadURL = (format, sig) => { | ||
let decodedUrl; | ||
@@ -207,5 +206,2 @@ if (format.url) { | ||
} else { | ||
if (debug) { | ||
console.warn(`Download url not found for itag ${format.itag}`); // eslint-disable-line no-console | ||
} | ||
return; | ||
@@ -217,5 +213,2 @@ } | ||
} catch (err) { | ||
if (debug) { | ||
console.warn(`Could not decode url: ${err.message}`); // eslint-disable-line no-console | ||
} | ||
return; | ||
@@ -265,3 +258,3 @@ } | ||
const sig = tokens && format.s ? exports.decipher(tokens, format.s) : null; | ||
exports.setDownloadURL(format, sig, options.debug); | ||
exports.setDownloadURL(format, sig); | ||
decipheredFormats[format.itag] = format; | ||
@@ -268,0 +261,0 @@ }); |
@@ -441,1 +441,23 @@ const url = require('url'); | ||
}; | ||
/** | ||
* Temporary helper to help deprecating a few properties. | ||
* | ||
* @param {Object} obj | ||
* @param {string} prop | ||
* @param {Object} value | ||
* @param {string} oldPath | ||
* @param {string} newPath | ||
*/ | ||
exports.deprecate = (obj, prop, value, oldPath, newPath) => { | ||
Object.defineProperty(obj, prop, { | ||
get: () => { | ||
// eslint-disable-next-line no-console | ||
console.warn( | ||
`\`${oldPath}\` will be removed in a near future release, ` + | ||
`use \`${newPath}\` instead.`); | ||
return value; | ||
}, | ||
}); | ||
}; |
@@ -9,3 +9,3 @@ { | ||
], | ||
"version": "2.1.5", | ||
"version": "3.0.0", | ||
"repository": { | ||
@@ -39,3 +39,3 @@ "type": "git", | ||
"m3u8stream": "^0.7.1", | ||
"miniget": "^1.7.2", | ||
"miniget": "^2.0.0", | ||
"sax": "^1.1.3" | ||
@@ -42,0 +42,0 @@ }, |
@@ -84,9 +84,9 @@ # node-ytdl-core | ||
### ytdl.getBasicInfo(url, [options], [callback(err, info)]) | ||
### async ytdl.getBasicInfo(url, [options]) | ||
Use this if you only want to get metainfo from a video. If `callback` isn't given, returns a promise. | ||
Use this if you only want to get metainfo from a video. | ||
### ytdl.getInfo(url, [options], [callback(err, info)]) | ||
### async ytdl.getInfo(url, [options]) | ||
Gets metainfo from a video. Includes additional formats, and ready to download deciphered URL. This is what the `ytdl()` function uses internally. If `callback` isn't given, returns a promise. | ||
Gets metainfo from a video. Includes additional formats, and ready to download deciphered URL. This is what the `ytdl()` function uses internally. | ||
@@ -104,9 +104,5 @@ ### ytdl.downloadFromInfo(info, options) | ||
// Example of choosing a video format. | ||
ytdl.getInfo(videoID, (err, info) => { | ||
if (err) throw err; | ||
let format = ytdl.chooseFormat(info.formats, { quality: '134' }); | ||
if (format) { | ||
console.log('Format found!'); | ||
} | ||
}); | ||
let info = await ytdl.getInfo(videoID); | ||
let format = ytdl.chooseFormat(info.formats, { quality: '134' }); | ||
console.log('Format found!', format); | ||
``` | ||
@@ -120,7 +116,5 @@ | ||
// Example of filtering the formats to audio only. | ||
ytdl.getInfo(videoID, (err, info) => { | ||
if (err) throw err; | ||
let audioFormats = ytdl.filterFormats(info.formats, 'audioonly'); | ||
console.log('Formats with only audio: ' + audioFormats.length); | ||
}); | ||
let info = await ytdl.getInfo(videoID); | ||
let audioFormats = ytdl.filterFormats(info.formats, 'audioonly'); | ||
console.log('Formats with only audio: ' + audioFormats.length); | ||
``` | ||
@@ -165,3 +159,3 @@ | ||
If you'd like to help fix the issue, look at the type of error first. The most common one is | ||
If you'd like to help fix the issue, look at the type of error first. If you're getting the following error | ||
@@ -174,3 +168,3 @@ Could not extract signature deciphering actions | ||
These tests are not mocked, and they actually try to start downloading a few videos. If these fail, then it's time to debug. | ||
These tests are not mocked, and they try to start downloading a few videos. If these fail, then it's time to debug. | ||
@@ -177,0 +171,0 @@ For getting started with that, you can look at the `extractActions()` function in [`/lib/sig.js`](https://github.com/fent/node-ytdl-core/blob/master/lib/sig.js). |
@@ -77,2 +77,94 @@ declare module 'ytdl-core' { | ||
interface VideoDetails { | ||
videoId: string; | ||
title: string; | ||
shortDescription: string; | ||
lengthSeconds: string; | ||
keywords: string[]; | ||
channelId: string; | ||
isCrawlable: boolean; | ||
thumbnail: { | ||
thumbnails: thumbnail[]; | ||
}; | ||
averageRating: number; | ||
allowRatings: boolean; | ||
viewCount: string; | ||
author: string; | ||
isPrivate: boolean; | ||
isUnpluggedCorpus: boolean | ||
isLiveContent: boolean; | ||
} | ||
interface Media { | ||
image?: string; | ||
category: string; | ||
category_url: string; | ||
game?: string; | ||
game_url?: string; | ||
year?: number; | ||
song?: string; | ||
artist?: string; | ||
artist_url?: string; | ||
writers?: string; | ||
licensed_by?: string; | ||
} | ||
interface Author { | ||
id: string; | ||
name: string; | ||
avatar: string; | ||
verified: boolean; | ||
user: string; | ||
channel_url: string; | ||
external_channel_url: string; | ||
user_url: string; | ||
subscriber_count: number; | ||
} | ||
interface MicroformatRenderer { | ||
thumbnail: { | ||
thumbnails: thumbnail[]; | ||
}; | ||
embed: { | ||
iframeUrl: string; | ||
flashUrl: string; | ||
width: number; | ||
height: number; | ||
flashSecureUrl: string; | ||
}; | ||
title: { | ||
simpleText: string; | ||
}; | ||
description: { | ||
simpleText: string; | ||
}; | ||
lengthSeconds: string; | ||
ownerProfileUrl: string; | ||
ownerGplusProfileUrl: string; | ||
externalChannelId: string; | ||
isFamilySafe: boolean; | ||
availableCountries: string[]; | ||
isUnlisted: boolean; | ||
hasYpcMetadata: boolean; | ||
viewCount: string; | ||
category: string; | ||
publishDate: string; | ||
ownerChannelName: string; | ||
liveBroadcastDetails?: { | ||
isLiveNow: boolean; | ||
startTimestamp: string; | ||
} | ||
uploadDate: string; | ||
} | ||
interface MoreVideoDetails extends Omit<VideoDetails, 'author'>, Omit<MicroformatRenderer, 'title' | 'description'> { | ||
published: number; | ||
video_url: string; | ||
age_restricted: boolean; | ||
likes?: number; | ||
dislikes?: number; | ||
media: Media; | ||
author: Author; | ||
} | ||
type videoInfo = { | ||
@@ -115,26 +207,4 @@ iv_load_policy?: string; | ||
pltype: string; | ||
media: { | ||
image?: string; | ||
category: string; | ||
category_url: string; | ||
game?: string; | ||
game_url?: string; | ||
year?: number; | ||
song?: string; | ||
artist?: string; | ||
artist_url?: string; | ||
writers?: string; | ||
licensed_by?: string; | ||
}; | ||
author: { | ||
id: string; | ||
name: string; | ||
avatar: string; | ||
verified: boolean; | ||
user: string; | ||
channel_url: string; | ||
external_channel_url: string; | ||
user_url: string; | ||
subscriber_count: number; | ||
}; | ||
media: Media; | ||
author: Author; | ||
enabled_engage_types: string; | ||
@@ -241,49 +311,7 @@ hl: string; | ||
microformat: { | ||
playerMicroformatRenderer: { | ||
thumbnail: { | ||
thumbnails: thumbnail[]; | ||
}; | ||
embed: { | ||
iframeUrl: string; | ||
flashUrl: string; | ||
width: number; | ||
height: number; | ||
flashSecureUrl: string; | ||
}; | ||
title: { | ||
simpleText: string; | ||
}; | ||
description: { | ||
simpleText: string; | ||
}; | ||
lengthSeconds: string; | ||
ownerProfileUrl: string; | ||
ownerGplusProfileUrl: string; | ||
externalChannelId: string; | ||
isFamilySafe: boolean; | ||
availableCountries: string[]; | ||
isUnlisted: boolean; | ||
hasYpcMetadata: boolean; | ||
viewCount: string; | ||
category: string; | ||
publishDate: string; | ||
ownerChannelName: string; | ||
uploadDate: string; | ||
}; | ||
playerMicroformatRenderer: MicroformatRenderer; | ||
}; | ||
videoDetails: { | ||
videoId: string; | ||
title: string; | ||
lengthSeconds: number; | ||
keywords: string[]; | ||
channelId: string; | ||
isCrawlable: boolean; | ||
thumbnail: { | ||
thumbnails: thumbnail[]; | ||
}; | ||
viewCount: number; | ||
author: string; | ||
isLiveContent: boolean; | ||
}; | ||
videoDetails: VideoDetails; | ||
}; | ||
videoDetails: MoreVideoDetails; | ||
} | ||
@@ -310,6 +338,6 @@ | ||
function getBasicInfo(url: string, callback?: (err: Error, info: videoInfo) => void): Promise<videoInfo>; | ||
function getBasicInfo(url: string, options?: downloadOptions, callback?: (err: Error, info: videoInfo) => void): Promise<videoInfo>; | ||
function getInfo(url: string, callback?: (err: Error, info: videoInfo) => void): Promise<videoInfo>; | ||
function getInfo(url: string, options?: downloadOptions, callback?: (err: Error, info: videoInfo) => void): Promise<videoInfo>; | ||
function getBasicInfo(url: string): Promise<videoInfo>; | ||
function getBasicInfo(url: string, options?: downloadOptions): Promise<videoInfo>; | ||
function getInfo(url: string): Promise<videoInfo>; | ||
function getInfo(url: string, options?: downloadOptions): Promise<videoInfo>; | ||
function downloadFromInfo(info: videoInfo, options?: downloadOptions): Readable; | ||
@@ -316,0 +344,0 @@ function chooseFormat(format: videoFormat | videoFormat[], options?: downloadOptions): videoFormat | never; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
74174
2047
204
+ Addedminiget@2.1.0(transitive)
Updatedminiget@^2.0.0