Add livestream support

This commit is contained in:
Max Isom 2020-03-14 21:48:08 -05:00
parent ad4d49f763
commit 2f0acaa858
3 changed files with 46 additions and 25 deletions

View file

@ -25,6 +25,7 @@
},
"devDependencies": {
"@types/bluebird": "^3.5.30",
"@types/fluent-ffmpeg": "^2.1.14",
"@types/fs-capacitor": "^2.0.0",
"@types/node": "^13.9.1",
"@types/spotify-web-api-node": "^4.0.1",
@ -68,6 +69,7 @@
"delay": "^4.3.0",
"discord.js": "^12.0.2",
"dotenv": "^8.2.0",
"fluent-ffmpeg": "^2.1.2",
"fs-capacitor": "^6.1.0",
"got": "^10.6.0",
"hasha": "^5.2.0",
@ -76,7 +78,6 @@
"make-dir": "^3.0.2",
"node-emoji": "^1.10.0",
"p-limit": "^2.2.2",
"prism-media": "^1.2.1",
"sequelize": "^5.21.5",
"sequelize-typescript": "^1.1.0",
"spotify-uri": "^2.0.0",

View file

@ -1,12 +1,12 @@
import {inject, injectable} from 'inversify';
import {VoiceConnection, VoiceChannel} from 'discord.js';
import {promises as fs, createWriteStream} from 'fs';
import {Readable} from 'stream';
import {Readable, PassThrough} from 'stream';
import path from 'path';
import hasha from 'hasha';
import ytdl from 'ytdl-core';
import {WriteStream} from 'fs-capacitor';
import prism from 'prism-media';
import ffmpeg from 'fluent-ffmpeg';
import {TYPES} from '../types';
import Queue, {QueuedSong} from './queue';
@ -185,7 +185,13 @@ export default class {
let format = formats.find(filter);
let canDirectPlay = true;
const nextBestFormat = (formats: ytdl.videoFormat[]): ytdl.videoFormat => {
const nextBestFormat = (formats: ytdl.videoFormat[]): ytdl.videoFormat | undefined => {
if (formats[0].live) {
formats = formats.sort((a, b) => (b as any).audioBitrate - (a as any).audioBitrate); // Bad typings
return formats.find(format => [128, 127, 120, 96, 95, 94, 93].includes(parseInt(format.itag as unknown as string, 10))); // Bad typings
}
formats = formats
.filter(format => format.averageBitrate)
.sort((a, b) => b.averageBitrate - a.averageBitrate);
@ -195,6 +201,11 @@ export default class {
if (!format) {
format = nextBestFormat(info.formats);
canDirectPlay = false;
if (!format) {
// If still no format is found, throw
throw new Error('Can\'t find suitable format.');
}
}
const cacheTempPath = this.getCachedPathTemp(url);
@ -209,25 +220,14 @@ export default class {
if (canDirectPlay) {
youtubeStream = ytdl.downloadFromInfo(info, {format});
} else {
youtubeStream = new prism.FFmpeg({
args: [
youtubeStream = ffmpeg(format.url).inputOptions([
'-reconnect',
'1',
'-reconnect_streamed',
'1',
'-reconnect_delay_max',
'5',
'-i',
format.url,
'-loglevel',
'verbose',
'-vn',
'-acodec',
'libopus',
'-f',
'webm'
]
});
'5'
]).noVideo().audioCodec('libopus').outputFormat('webm').pipe() as PassThrough;
}
const capacitor = new WriteStream();

View file

@ -75,6 +75,13 @@
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
"@types/fluent-ffmpeg@^2.1.14":
version "2.1.14"
resolved "https://registry.yarnpkg.com/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.14.tgz#b21d60267fe269c2ea81fa3238a36a8349f8f2f3"
integrity sha512-nJrAX9ODNI7mUB0b7Y0Stx1a6dOpV3zXsOnWoBuEd9/woQhepBNCMeCyOL6SLJD3jn5sLw5ciDGH0RwJenCoag==
dependencies:
"@types/node" "*"
"@types/fs-capacitor@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz#17113e25817f584f58100fb7a08eed288b81956e"
@ -329,6 +336,11 @@ astral-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
async@>=0.2.9:
version "3.2.0"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@ -1038,6 +1050,14 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
fluent-ffmpeg@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74"
integrity sha1-yVLeIkD4EuvaCqgAbXd27irPfXQ=
dependencies:
async ">=0.2.9"
which "^1.1.1"
follow-redirects@1.5.10:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
@ -2128,7 +2148,7 @@ prepend-http@^1.0.1:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
prism-media@^1.0.1, prism-media@^1.2.0, prism-media@^1.2.1:
prism-media@^1.0.1, prism-media@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.2.1.tgz#168f323712bcaacb1d70ae613bf9d9dc44cf43d4"
integrity sha512-R3EbKwJiYlTvGwcG1DpUt+06DsxOGS5W4AMEHT7oVOjG93MjpdhGX1whHyjnqknylLMupKAsKMEXcTNRbPe6Vw==
@ -2856,7 +2876,7 @@ which-pm-runs@^1.0.0:
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
which@^1.2.9:
which@^1.1.1, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==