From 2f0acaa858a5b76fc4c38b7c1458c5f9e67c657b Mon Sep 17 00:00:00 2001 From: Max Isom Date: Sat, 14 Mar 2020 21:48:08 -0500 Subject: [PATCH] Add livestream support --- package.json | 3 ++- src/services/player.ts | 44 +++++++++++++++++++++--------------------- yarn.lock | 24 +++++++++++++++++++++-- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 0e669f1..240cf63 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/services/player.ts b/src/services/player.ts index 1970cc7..88457ce 100644 --- a/src/services/player.ts +++ b/src/services/player.ts @@ -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: [ - '-reconnect', - '1', - '-reconnect_streamed', - '1', - '-reconnect_delay_max', - '5', - '-i', - format.url, - '-loglevel', - 'verbose', - '-vn', - '-acodec', - 'libopus', - '-f', - 'webm' - ] - }); + youtubeStream = ffmpeg(format.url).inputOptions([ + '-reconnect', + '1', + '-reconnect_streamed', + '1', + '-reconnect_delay_max', + '5' + ]).noVideo().audioCodec('libopus').outputFormat('webm').pipe() as PassThrough; } const capacitor = new WriteStream(); diff --git a/yarn.lock b/yarn.lock index e270864..8086009 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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==