2020-09-23 16:47:12 +02:00
|
|
|
const discordclientmanager = require("./discordclientmanager");
|
2020-09-21 04:05:49 +02:00
|
|
|
const {
|
2020-09-21 05:30:39 +02:00
|
|
|
getAudioDispatcher,
|
|
|
|
setAudioDispatcher
|
|
|
|
} = require("./dispachermanager");
|
2020-09-23 16:47:12 +02:00
|
|
|
const {
|
|
|
|
ticksToSeconds
|
|
|
|
} = require("./util");
|
2020-09-21 04:05:49 +02:00
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
// this whole thing should be a class but its probably too late now.
|
2020-09-24 13:34:39 +02:00
|
|
|
|
|
|
|
var currentPlayingPlaylist;
|
|
|
|
var currentPlayingPlaylistIndex;
|
2020-09-21 04:05:49 +02:00
|
|
|
var progressInterval;
|
|
|
|
var isPaused;
|
2020-09-24 13:34:39 +02:00
|
|
|
var isRepeat;
|
2020-09-23 16:47:12 +02:00
|
|
|
var _disconnectOnFinish;
|
|
|
|
var _seek;
|
2020-09-21 04:05:49 +02:00
|
|
|
|
2020-09-21 05:30:39 +02:00
|
|
|
const jellyfinClientManager = require("./jellyfinclientmanager");
|
2020-09-24 13:34:39 +02:00
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function streamURLbuilder (itemID, bitrate) {
|
2020-09-21 05:30:39 +02:00
|
|
|
// so the server transcodes. Seems appropriate as it has the source file.
|
|
|
|
const supportedCodecs = "opus";
|
|
|
|
const supportedContainers = "ogg,opus";
|
|
|
|
return `${jellyfinClientManager.getJellyfinClient().serverAddress()}/Audio/${itemID}/universal?UserId=${jellyfinClientManager.getJellyfinClient().getCurrentUserId()}&DeviceId=${jellyfinClientManager.getJellyfinClient().deviceId()}&MaxStreamingBitrate=${bitrate}&Container=${supportedContainers}&AudioCodec=${supportedCodecs}&api_key=${jellyfinClientManager.getJellyfinClient().accessToken()}&TranscodingContainer=ts&TranscodingProtocol=hls`;
|
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function startPlaying (voiceconnection = discordclientmanager.getDiscordClient().user.client.voice.connections.first(), itemIDPlaylist = currentPlayingPlaylist, playlistIndex = currentPlayingPlaylistIndex, seekTo, disconnectOnFinish = _disconnectOnFinish) {
|
2020-09-21 05:30:39 +02:00
|
|
|
isPaused = false;
|
2020-09-24 13:34:39 +02:00
|
|
|
currentPlayingPlaylist = itemIDPlaylist;
|
|
|
|
currentPlayingPlaylistIndex = playlistIndex;
|
2020-09-23 16:47:12 +02:00
|
|
|
_disconnectOnFinish = disconnectOnFinish;
|
2020-09-23 17:06:20 +02:00
|
|
|
_seek = seekTo * 1000;
|
2020-09-24 13:37:17 +02:00
|
|
|
async function playasync () {
|
2020-09-24 13:34:39 +02:00
|
|
|
const url = streamURLbuilder(itemIDPlaylist[playlistIndex], voiceconnection.channel.bitrate);
|
|
|
|
setAudioDispatcher(voiceconnection.play(url, {
|
|
|
|
seek: seekTo
|
|
|
|
}));
|
2020-09-23 17:06:20 +02:00
|
|
|
if (seekTo) {
|
2020-09-23 16:47:12 +02:00
|
|
|
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
2020-09-23 17:06:20 +02:00
|
|
|
} else {
|
2020-09-24 13:34:39 +02:00
|
|
|
jellyfinClientManager.getJellyfinClient().reportPlaybackStart({
|
|
|
|
userID: `${jellyfinClientManager.getJellyfinClient().getCurrentUserId()}`,
|
|
|
|
itemID: `${itemIDPlaylist[playlistIndex]}`,
|
|
|
|
canSeek: true,
|
|
|
|
playSessionId: getPlaySessionId(),
|
|
|
|
playMethod: getPlayMethod()
|
|
|
|
});
|
2020-09-23 16:47:12 +02:00
|
|
|
}
|
2020-09-21 05:30:39 +02:00
|
|
|
|
|
|
|
getAudioDispatcher().on("finish", () => {
|
2020-09-24 13:34:39 +02:00
|
|
|
if (currentPlayingPlaylist.length < playlistIndex) {
|
|
|
|
if (disconnectOnFinish) {
|
|
|
|
stop(voiceconnection, currentPlayingPlaylist[playlistIndex - 1]);
|
2020-09-24 13:37:17 +02:00
|
|
|
} else {
|
2020-09-24 13:34:39 +02:00
|
|
|
stop(undefined, currentPlayingPlaylist[playlistIndex - 1]);
|
|
|
|
}
|
2020-09-21 05:30:39 +02:00
|
|
|
} else {
|
2020-09-24 13:37:17 +02:00
|
|
|
startPlaying(voiceconnection, itemIDPlaylist, currentPlayingPlaylistIndex + 1, 0);
|
2020-09-21 05:30:39 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2020-09-24 13:34:39 +02:00
|
|
|
playasync().catch((rsn) => {
|
|
|
|
console.error(rsn);
|
|
|
|
});
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
2020-09-23 16:47:12 +02:00
|
|
|
/**
|
|
|
|
* @param {Number} toSeek - where to seek in ticks
|
|
|
|
*/
|
2020-09-24 13:37:17 +02:00
|
|
|
function seek (toSeek = 0) {
|
2020-09-23 17:06:20 +02:00
|
|
|
if (getAudioDispatcher()) {
|
2020-09-24 13:34:39 +02:00
|
|
|
startPlaying(undefined, undefined, undefined, ticksToSeconds(toSeek), _disconnectOnFinish);
|
2020-09-23 16:47:12 +02:00
|
|
|
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
2020-09-23 17:42:13 +02:00
|
|
|
} else {
|
2020-09-23 17:39:41 +02:00
|
|
|
throw Error("No Song Playing");
|
2020-09-23 16:47:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function nextTrack () {
|
|
|
|
// console.log(currentPlayingPlaylistIndex + 1, currentPlayingPlaylist.length);
|
|
|
|
if (!(currentPlayingPlaylist)) {
|
2020-09-24 13:34:39 +02:00
|
|
|
throw Error("There is currently nothing playing");
|
2020-09-24 13:37:17 +02:00
|
|
|
} else if (currentPlayingPlaylistIndex + 1 >= currentPlayingPlaylist.length) {
|
2020-09-24 13:34:39 +02:00
|
|
|
throw Error("This is the Last song");
|
|
|
|
}
|
2020-09-24 13:37:17 +02:00
|
|
|
startPlaying(undefined, undefined, currentPlayingPlaylistIndex + 1, 0, _disconnectOnFinish);
|
2020-09-24 13:34:39 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function previousTrack () {
|
|
|
|
if (ticksToSeconds(getPostitionTicks()) < 10) {
|
|
|
|
if (!(currentPlayingPlaylist)) {
|
2020-09-24 13:34:39 +02:00
|
|
|
throw Error("There is currently nothing playing");
|
2020-09-24 13:37:17 +02:00
|
|
|
} else if (currentPlayingPlaylistIndex - 1 < 0) {
|
|
|
|
startPlaying(undefined, undefined, currentPlayingPlaylistIndex, 0, _disconnectOnFinish);
|
2020-09-24 13:34:39 +02:00
|
|
|
throw Error("This is the First song");
|
|
|
|
}
|
2020-09-24 13:37:17 +02:00
|
|
|
startPlaying(undefined, undefined, currentPlayingPlaylistIndex - 1, 0, _disconnectOnFinish);
|
2020-09-24 13:34:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-21 04:05:49 +02:00
|
|
|
/**
|
|
|
|
* @param {Object=} disconnectVoiceConnection - Optional The voice Connection do disconnect from
|
|
|
|
*/
|
2020-09-24 13:37:17 +02:00
|
|
|
function stop (disconnectVoiceConnection, itemId = getItemId()) {
|
2020-09-21 05:30:39 +02:00
|
|
|
isPaused = true;
|
|
|
|
if (disconnectVoiceConnection) {
|
|
|
|
disconnectVoiceConnection.disconnect();
|
|
|
|
}
|
2020-09-24 13:34:39 +02:00
|
|
|
jellyfinClientManager.getJellyfinClient().reportPlaybackStopped({
|
|
|
|
userId: jellyfinClientManager.getJellyfinClient().getCurrentUserId(),
|
|
|
|
itemId: itemId,
|
|
|
|
playSessionId: getPlaySessionId()
|
|
|
|
});
|
|
|
|
if (getAudioDispatcher()) {
|
|
|
|
getAudioDispatcher().destroy();
|
|
|
|
}
|
2020-09-21 05:30:39 +02:00
|
|
|
setAudioDispatcher(undefined);
|
|
|
|
clearInterval(progressInterval);
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
2020-09-24 13:34:39 +02:00
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function pause () {
|
2020-09-21 05:30:39 +02:00
|
|
|
isPaused = true;
|
|
|
|
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
|
|
|
getAudioDispatcher().pause(true);
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
2020-09-24 13:34:39 +02:00
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function resume () {
|
2020-09-21 05:30:39 +02:00
|
|
|
isPaused = false;
|
|
|
|
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
|
|
|
getAudioDispatcher().resume();
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
2020-09-24 13:34:39 +02:00
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function playPause () {
|
|
|
|
if (!(getAudioDispatcher())) {
|
2020-09-24 13:34:39 +02:00
|
|
|
throw Error("There is nothing Playing right now!");
|
|
|
|
}
|
|
|
|
if (getAudioDispatcher().paused) {
|
|
|
|
resume();
|
|
|
|
} else {
|
|
|
|
pause();
|
|
|
|
}
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getPostitionTicks () {
|
2020-09-21 05:30:39 +02:00
|
|
|
// this is very sketchy but i dont know how else to do it
|
2020-09-23 17:06:20 +02:00
|
|
|
return (_seek + getAudioDispatcher().streamTime - getAudioDispatcher().pausedTime) * 10000;
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getPlayMethod () {
|
2020-09-21 05:30:39 +02:00
|
|
|
// TODO figure out how to figure this out
|
2020-09-24 13:34:39 +02:00
|
|
|
return "Transcode";
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getRepeatMode () {
|
|
|
|
if (isRepeat) {
|
2020-09-24 13:34:39 +02:00
|
|
|
return "RepeatOne";
|
2020-09-24 13:37:17 +02:00
|
|
|
} else {
|
2020-09-24 13:34:39 +02:00
|
|
|
return "RepeatNone";
|
|
|
|
}
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getPlaylistItemId () {
|
2020-09-24 13:34:39 +02:00
|
|
|
return getItemId();
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getPlaySessionId () {
|
2020-09-21 05:30:39 +02:00
|
|
|
// i think its just a number which you dont need to retrieve but need to report
|
|
|
|
return "ae2436edc6b91b11d72aeaa67f84e0ea";
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getNowPLayingQueue () {
|
2020-09-21 05:30:39 +02:00
|
|
|
return [{
|
2020-09-24 13:34:39 +02:00
|
|
|
Id: getItemId(),
|
2020-09-21 05:30:39 +02:00
|
|
|
// as I curently dont support Playlists
|
|
|
|
PlaylistItemId: getPlaylistItemId()
|
|
|
|
}];
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getCanSeek () {
|
2020-09-23 16:47:12 +02:00
|
|
|
return true;
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getIsMuted () {
|
2020-09-21 05:30:39 +02:00
|
|
|
return false;
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getVolumeLevel () {
|
2020-09-21 05:30:39 +02:00
|
|
|
return 100;
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getItemId () {
|
2020-09-24 13:34:39 +02:00
|
|
|
return currentPlayingPlaylist[currentPlayingPlaylistIndex];
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getIsPaused () {
|
2020-09-21 05:30:39 +02:00
|
|
|
// AudioDispacker Paused is to slow
|
2020-09-21 04:05:49 +02:00
|
|
|
|
2020-09-21 05:30:39 +02:00
|
|
|
if (isPaused === undefined) {
|
|
|
|
isPaused = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return isPaused;
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function setIsRepeat (arg) {
|
|
|
|
isRepeat = arg;
|
2020-09-24 13:34:39 +02:00
|
|
|
}
|
|
|
|
|
2020-09-24 13:37:17 +02:00
|
|
|
function getProgressPayload () {
|
2020-09-21 05:30:39 +02:00
|
|
|
const payload = {
|
|
|
|
CanSeek: getCanSeek(),
|
|
|
|
IsMuted: getIsMuted(),
|
|
|
|
IsPaused: getIsPaused(),
|
|
|
|
ItemId: getItemId(),
|
|
|
|
MediaSourceId: getItemId(),
|
|
|
|
NowPlayingQueue: getNowPLayingQueue(),
|
|
|
|
PlayMethod: getPlayMethod(),
|
|
|
|
PlaySessionId: getPlaySessionId(),
|
|
|
|
PlaylistItemId: getPlaylistItemId(),
|
|
|
|
PositionTicks: getPostitionTicks(),
|
|
|
|
RepeatMode: getRepeatMode(),
|
2020-09-21 09:56:46 +02:00
|
|
|
VolumeLevel: getVolumeLevel(),
|
|
|
|
EventName: "pauseplayupdate"
|
2020-09-21 05:30:39 +02:00
|
|
|
};
|
|
|
|
return payload;
|
2020-09-21 04:05:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
2020-09-21 05:30:39 +02:00
|
|
|
startPlaying,
|
|
|
|
stop,
|
|
|
|
playPause,
|
|
|
|
resume,
|
2020-09-23 16:47:12 +02:00
|
|
|
pause,
|
2020-09-24 13:34:39 +02:00
|
|
|
seek,
|
|
|
|
setIsRepeat,
|
|
|
|
nextTrack,
|
|
|
|
previousTrack,
|
|
|
|
getPostitionTicks
|
2020-09-24 13:37:17 +02:00
|
|
|
};
|