mirror of
https://github.com/informaticker/discord-jellyfin-bot.git
synced 2024-11-23 18:21:55 +01:00
add playlist support
This commit is contained in:
parent
bd4ad6b424
commit
e019f4c6e5
@ -121,7 +121,7 @@ async function playThis (message) {
|
|||||||
|
|
||||||
discordClient.user.client.voice.connections.forEach((element) => {
|
discordClient.user.client.voice.connections.forEach((element) => {
|
||||||
songPlayMessage(message, argument);
|
songPlayMessage(message, argument);
|
||||||
playbackmanager.startPlaying(element, itemID, 0, isSummendByPlay);
|
playbackmanager.startPlaying(element, [itemID], 0, 0, isSummendByPlay);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,19 +149,16 @@ function handleChannelMessage (message) {
|
|||||||
.setDescription("<:wave:757938481585586226> " + desc);
|
.setDescription("<:wave:757938481585586226> " + desc);
|
||||||
message.channel.send(vcJoin);
|
message.channel.send(vcJoin);
|
||||||
} else if ((message.content.startsWith(CONFIG["discord-prefix"] + "pause")) || (message.content.startsWith(CONFIG["discord-prefix"] + "resume"))) {
|
} else if ((message.content.startsWith(CONFIG["discord-prefix"] + "pause")) || (message.content.startsWith(CONFIG["discord-prefix"] + "resume"))) {
|
||||||
if (getAudioDispatcher() !== undefined) {
|
try {
|
||||||
playbackmanager.playPause();
|
playbackmanager.playPause();
|
||||||
const noPlay = new Discord.MessageEmbed()
|
const noPlay = new Discord.MessageEmbed()
|
||||||
.setColor(0xff0000)
|
.setColor(0xff0000)
|
||||||
.setTitle("<:play_pause:757940598106882049> " + "Paused/Resumed.")
|
.setTitle("<:play_pause:757940598106882049> " + "Paused/Resumed.")
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
message.channel.send(noPlay);
|
message.channel.send(noPlay);
|
||||||
} else {
|
} catch (error) {
|
||||||
const noPlay = new Discord.MessageEmbed()
|
const errorMessage = getDiscordEmbedError(error);
|
||||||
.setColor(0xff0000)
|
message.channel.send(errorMessage);
|
||||||
.setTitle("<:x:757935515445231651> " + "There is nothing Playing right now!")
|
|
||||||
.setTimestamp();
|
|
||||||
message.channel.send(noPlay);
|
|
||||||
}
|
}
|
||||||
} else if (message.content.startsWith(CONFIG["discord-prefix"] + "play")) {
|
} else if (message.content.startsWith(CONFIG["discord-prefix"] + "play")) {
|
||||||
if (discordClient.user.client.voice.connections.size < 1) {
|
if (discordClient.user.client.voice.connections.size < 1) {
|
||||||
@ -187,6 +184,13 @@ function handleChannelMessage (message) {
|
|||||||
const errorMessage = getDiscordEmbedError(error);
|
const errorMessage = getDiscordEmbedError(error);
|
||||||
message.channel.send(errorMessage);
|
message.channel.send(errorMessage);
|
||||||
}
|
}
|
||||||
|
} else if (message.content.startsWith(CONFIG["discord-prefix"] + "skip")) {
|
||||||
|
try {
|
||||||
|
playbackmanager.nextTrack()
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = getDiscordEmbedError(error);
|
||||||
|
message.channel.send(errorMessage);
|
||||||
|
}
|
||||||
} else if (message.content.startsWith(CONFIG["discord-prefix"] + "help")) {
|
} else if (message.content.startsWith(CONFIG["discord-prefix"] + "help")) {
|
||||||
/* eslint-disable quotes */
|
/* eslint-disable quotes */
|
||||||
const reply = new Discord.MessageEmbed()
|
const reply = new Discord.MessageEmbed()
|
||||||
@ -207,6 +211,9 @@ function handleChannelMessage (message) {
|
|||||||
}, {
|
}, {
|
||||||
name: `${CONFIG["discord-prefix"]}seek`,
|
name: `${CONFIG["discord-prefix"]}seek`,
|
||||||
value: "Where to Seek to in seconds or MM:SS"
|
value: "Where to Seek to in seconds or MM:SS"
|
||||||
|
}, {
|
||||||
|
name: `${CONFIG["discord-prefix"]}skip`,
|
||||||
|
value: "Skip this Song"
|
||||||
}, {
|
}, {
|
||||||
name: `${CONFIG["discord-prefix"]}help`,
|
name: `${CONFIG["discord-prefix"]}help`,
|
||||||
value: "Display this help message"
|
value: "Display this help message"
|
||||||
|
@ -7,132 +7,201 @@ const {
|
|||||||
ticksToSeconds
|
ticksToSeconds
|
||||||
} = require("./util");
|
} = require("./util");
|
||||||
|
|
||||||
var currentPlayingItemId;
|
|
||||||
|
//this whole thing should be a class but its probably too late now.
|
||||||
|
|
||||||
|
var currentPlayingPlaylist;
|
||||||
|
var currentPlayingPlaylistIndex;
|
||||||
var progressInterval;
|
var progressInterval;
|
||||||
var isPaused;
|
var isPaused;
|
||||||
|
var isRepeat;
|
||||||
var _disconnectOnFinish;
|
var _disconnectOnFinish;
|
||||||
var _seek;
|
var _seek;
|
||||||
|
|
||||||
const jellyfinClientManager = require("./jellyfinclientmanager");
|
const jellyfinClientManager = require("./jellyfinclientmanager");
|
||||||
function streamURLbuilder (itemID, bitrate) {
|
|
||||||
|
function streamURLbuilder(itemID, bitrate) {
|
||||||
// so the server transcodes. Seems appropriate as it has the source file.
|
// so the server transcodes. Seems appropriate as it has the source file.
|
||||||
const supportedCodecs = "opus";
|
const supportedCodecs = "opus";
|
||||||
const supportedContainers = "ogg,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`;
|
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`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startPlaying (voiceconnection = discordclientmanager.getDiscordClient().user.client.voice.connections.first(), itemID = currentPlayingItemId, seekTo, disconnectOnFinish = _disconnectOnFinish) {
|
function startPlaying(voiceconnection = discordclientmanager.getDiscordClient().user.client.voice.connections.first(), itemIDPlaylist = currentPlayingPlaylist, playlistIndex = currentPlayingPlaylistIndex, seekTo, disconnectOnFinish = _disconnectOnFinish) {
|
||||||
isPaused = false;
|
isPaused = false;
|
||||||
currentPlayingItemId = itemID;
|
currentPlayingPlaylist = itemIDPlaylist;
|
||||||
|
currentPlayingPlaylistIndex = playlistIndex;
|
||||||
_disconnectOnFinish = disconnectOnFinish;
|
_disconnectOnFinish = disconnectOnFinish;
|
||||||
_seek = seekTo * 1000;
|
_seek = seekTo * 1000;
|
||||||
async function playasync () {
|
async function playasync() {
|
||||||
const url = streamURLbuilder(itemID, voiceconnection.channel.bitrate);
|
const url = streamURLbuilder(itemIDPlaylist[playlistIndex], voiceconnection.channel.bitrate);
|
||||||
setAudioDispatcher(voiceconnection.play(url, { seek: seekTo }));
|
setAudioDispatcher(voiceconnection.play(url, {
|
||||||
|
seek: seekTo
|
||||||
|
}));
|
||||||
if (seekTo) {
|
if (seekTo) {
|
||||||
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
||||||
} else {
|
} else {
|
||||||
jellyfinClientManager.getJellyfinClient().reportPlaybackStart({ userID: `${jellyfinClientManager.getJellyfinClient().getCurrentUserId()}`, itemID: `${itemID}`, canSeek: true, playSessionId: getPlaySessionId(), playMethod: getPlayMethod() });
|
jellyfinClientManager.getJellyfinClient().reportPlaybackStart({
|
||||||
|
userID: `${jellyfinClientManager.getJellyfinClient().getCurrentUserId()}`,
|
||||||
|
itemID: `${itemIDPlaylist[playlistIndex]}`,
|
||||||
|
canSeek: true,
|
||||||
|
playSessionId: getPlaySessionId(),
|
||||||
|
playMethod: getPlayMethod()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAudioDispatcher().on("finish", () => {
|
getAudioDispatcher().on("finish", () => {
|
||||||
if (disconnectOnFinish) {
|
if (currentPlayingPlaylist.length < playlistIndex) {
|
||||||
stop(voiceconnection);
|
console.log("PLAYLIST END")
|
||||||
|
|
||||||
|
if (disconnectOnFinish) {
|
||||||
|
stop(voiceconnection, currentPlayingPlaylist[playlistIndex - 1]);
|
||||||
|
}else {
|
||||||
|
stop(undefined, currentPlayingPlaylist[playlistIndex - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
stop();
|
startPlaying(voiceconnection, itemIDPlaylist, currentPlayingPlaylistIndex+1, 0)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
playasync().catch((rsn) => { console.error(rsn); });
|
playasync().catch((rsn) => {
|
||||||
|
console.error(rsn);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {Number} toSeek - where to seek in ticks
|
* @param {Number} toSeek - where to seek in ticks
|
||||||
*/
|
*/
|
||||||
function seek (toSeek = 0) {
|
function seek(toSeek = 0) {
|
||||||
if (getAudioDispatcher()) {
|
if (getAudioDispatcher()) {
|
||||||
startPlaying(undefined, undefined, ticksToSeconds(toSeek), _disconnectOnFinish);
|
startPlaying(undefined, undefined, undefined, ticksToSeconds(toSeek), _disconnectOnFinish);
|
||||||
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
||||||
} else {
|
} else {
|
||||||
throw Error("No Song Playing");
|
throw Error("No Song Playing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nextTrack(){
|
||||||
|
//console.log(currentPlayingPlaylistIndex + 1, currentPlayingPlaylist.length);
|
||||||
|
if(!(currentPlayingPlaylist)){
|
||||||
|
throw Error("There is currently nothing playing");
|
||||||
|
}else if(currentPlayingPlaylistIndex + 1 >= currentPlayingPlaylist.length){
|
||||||
|
throw Error("This is the Last song");
|
||||||
|
}
|
||||||
|
startPlaying(undefined, undefined, currentPlayingPlaylistIndex + 1, 0, _disconnectOnFinish)
|
||||||
|
}
|
||||||
|
|
||||||
|
function previousTrack(){
|
||||||
|
if(ticksToSeconds(getPostitionTicks())<10){
|
||||||
|
console.log(currentPlayingPlaylistIndex , currentPlayingPlaylist.length);
|
||||||
|
if(!(currentPlayingPlaylist)){
|
||||||
|
throw Error("There is currently nothing playing");
|
||||||
|
}else if(currentPlayingPlaylistIndex -1 < 0){
|
||||||
|
startPlaying(undefined, undefined, currentPlayingPlaylistIndex, 0, _disconnectOnFinish)
|
||||||
|
throw Error("This is the First song");
|
||||||
|
}
|
||||||
|
startPlaying(undefined, undefined, currentPlayingPlaylistIndex - 1, 0, _disconnectOnFinish)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object=} disconnectVoiceConnection - Optional The voice Connection do disconnect from
|
* @param {Object=} disconnectVoiceConnection - Optional The voice Connection do disconnect from
|
||||||
*/
|
*/
|
||||||
function stop (disconnectVoiceConnection) {
|
function stop(disconnectVoiceConnection, itemId = getItemId()) {
|
||||||
|
console.log("im getting called");
|
||||||
|
console
|
||||||
isPaused = true;
|
isPaused = true;
|
||||||
if (disconnectVoiceConnection) {
|
if (disconnectVoiceConnection) {
|
||||||
disconnectVoiceConnection.disconnect();
|
disconnectVoiceConnection.disconnect();
|
||||||
}
|
}
|
||||||
jellyfinClientManager.getJellyfinClient().reportPlaybackStopped({ userId: jellyfinClientManager.getJellyfinClient().getCurrentUserId(), itemId: currentPlayingItemId, playSessionId: getPlaySessionId() });
|
jellyfinClientManager.getJellyfinClient().reportPlaybackStopped({
|
||||||
if (getAudioDispatcher()) { getAudioDispatcher().destroy(); }
|
userId: jellyfinClientManager.getJellyfinClient().getCurrentUserId(),
|
||||||
|
itemId: itemId,
|
||||||
|
playSessionId: getPlaySessionId()
|
||||||
|
});
|
||||||
|
if (getAudioDispatcher()) {
|
||||||
|
getAudioDispatcher().destroy();
|
||||||
|
}
|
||||||
setAudioDispatcher(undefined);
|
setAudioDispatcher(undefined);
|
||||||
clearInterval(progressInterval);
|
clearInterval(progressInterval);
|
||||||
}
|
}
|
||||||
function pause () {
|
|
||||||
|
function pause() {
|
||||||
isPaused = true;
|
isPaused = true;
|
||||||
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
||||||
getAudioDispatcher().pause(true);
|
getAudioDispatcher().pause(true);
|
||||||
}
|
}
|
||||||
function resume () {
|
|
||||||
|
function resume() {
|
||||||
isPaused = false;
|
isPaused = false;
|
||||||
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload());
|
||||||
getAudioDispatcher().resume();
|
getAudioDispatcher().resume();
|
||||||
}
|
}
|
||||||
function playPause () {
|
|
||||||
if (getAudioDispatcher().paused) { resume(); } else { pause(); }
|
function playPause() {
|
||||||
|
if(!(getAudioDispatcher())){
|
||||||
|
throw Error("There is nothing Playing right now!");
|
||||||
|
}
|
||||||
|
if (getAudioDispatcher().paused) {
|
||||||
|
resume();
|
||||||
|
} else {
|
||||||
|
pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPostitionTicks () {
|
function getPostitionTicks() {
|
||||||
// this is very sketchy but i dont know how else to do it
|
// this is very sketchy but i dont know how else to do it
|
||||||
|
console.log((_seek + getAudioDispatcher().streamTime - getAudioDispatcher().pausedTime) * 10000);
|
||||||
return (_seek + getAudioDispatcher().streamTime - getAudioDispatcher().pausedTime) * 10000;
|
return (_seek + getAudioDispatcher().streamTime - getAudioDispatcher().pausedTime) * 10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlayMethod () {
|
function getPlayMethod() {
|
||||||
// TODO figure out how to figure this out
|
// TODO figure out how to figure this out
|
||||||
return 0;
|
return "Transcode";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRepeatMode () {
|
function getRepeatMode() {
|
||||||
return "RepeatNone";
|
if(isRepeat){
|
||||||
|
return "RepeatOne";
|
||||||
|
}else{
|
||||||
|
return "RepeatNone";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlaylistItemId () {
|
function getPlaylistItemId() {
|
||||||
// as I curently dont support Playlists
|
return getItemId();
|
||||||
return "playlistItem0";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlaySessionId () {
|
function getPlaySessionId() {
|
||||||
// i think its just a number which you dont need to retrieve but need to report
|
// i think its just a number which you dont need to retrieve but need to report
|
||||||
return "ae2436edc6b91b11d72aeaa67f84e0ea";
|
return "ae2436edc6b91b11d72aeaa67f84e0ea";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNowPLayingQueue () {
|
function getNowPLayingQueue() {
|
||||||
return [{
|
return [{
|
||||||
Id: currentPlayingItemId,
|
Id: getItemId(),
|
||||||
// as I curently dont support Playlists
|
// as I curently dont support Playlists
|
||||||
PlaylistItemId: getPlaylistItemId()
|
PlaylistItemId: getPlaylistItemId()
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCanSeek () {
|
function getCanSeek() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIsMuted () {
|
function getIsMuted() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVolumeLevel () {
|
function getVolumeLevel() {
|
||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getItemId () {
|
function getItemId() {
|
||||||
return currentPlayingItemId;
|
return currentPlayingPlaylist[currentPlayingPlaylistIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIsPaused () {
|
function getIsPaused() {
|
||||||
// AudioDispacker Paused is to slow
|
// AudioDispacker Paused is to slow
|
||||||
|
|
||||||
if (isPaused === undefined) {
|
if (isPaused === undefined) {
|
||||||
@ -142,7 +211,11 @@ function getIsPaused () {
|
|||||||
return isPaused;
|
return isPaused;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProgressPayload () {
|
function setIsRepeat(arg){
|
||||||
|
isRepeat=arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProgressPayload() {
|
||||||
const payload = {
|
const payload = {
|
||||||
CanSeek: getCanSeek(),
|
CanSeek: getCanSeek(),
|
||||||
IsMuted: getIsMuted(),
|
IsMuted: getIsMuted(),
|
||||||
@ -167,5 +240,9 @@ module.exports = {
|
|||||||
playPause,
|
playPause,
|
||||||
resume,
|
resume,
|
||||||
pause,
|
pause,
|
||||||
seek
|
seek,
|
||||||
|
setIsRepeat,
|
||||||
|
nextTrack,
|
||||||
|
previousTrack,
|
||||||
|
getPostitionTicks
|
||||||
};
|
};
|
@ -1,5 +1,6 @@
|
|||||||
const jellyfinClientManager = require("./jellyfinclientmanager");
|
const jellyfinClientManager = require("./jellyfinclientmanager");
|
||||||
const playbackmanager = require("./playbackmanager");
|
const playbackmanager = require("./playbackmanager");
|
||||||
|
const { ticksToSeconds }= require("./util");
|
||||||
|
|
||||||
function openSocket () {
|
function openSocket () {
|
||||||
jellyfinClientManager.getJellyfinClient().openWebSocket();
|
jellyfinClientManager.getJellyfinClient().openWebSocket();
|
||||||
@ -7,13 +8,14 @@ function openSocket () {
|
|||||||
{
|
{
|
||||||
PlayableMediaTypes: "Audio",
|
PlayableMediaTypes: "Audio",
|
||||||
SupportsMediaControl: "True",
|
SupportsMediaControl: "True",
|
||||||
SupportedCommands: "Play,Playstate"
|
SupportedCommands: "SetRepeatMode,Play,Playstate"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
jellyfinClientManager.getJellyfinEvents().on(jellyfinClientManager.getJellyfinClient(), "message", (type, data) => {
|
jellyfinClientManager.getJellyfinEvents().on(jellyfinClientManager.getJellyfinClient(), "message", (type, data) => {
|
||||||
|
console.log(data);
|
||||||
if (data.MessageType === "Play") {
|
if (data.MessageType === "Play") {
|
||||||
if (data.Data.PlayCommand === "PlayNow") {
|
if (data.Data.PlayCommand === "PlayNow") {
|
||||||
playbackmanager.startPlaying(undefined, data.Data.ItemIds[data.Data.StartIndex || 0], 0, false);
|
playbackmanager.startPlaying(undefined, data.Data.ItemIds, data.Data.StartIndex || 0, 0, false);
|
||||||
}
|
}
|
||||||
} else if (data.MessageType === "Playstate") {
|
} else if (data.MessageType === "Playstate") {
|
||||||
if (data.Data.Command === "PlayPause") {
|
if (data.Data.Command === "PlayPause") {
|
||||||
@ -21,7 +23,23 @@ function openSocket () {
|
|||||||
} else if (data.Data.Command === "Stop") {
|
} else if (data.Data.Command === "Stop") {
|
||||||
playbackmanager.stop();
|
playbackmanager.stop();
|
||||||
} else if (data.Data.Command === "Seek") {
|
} else if (data.Data.Command === "Seek") {
|
||||||
playbackmanager.seek(data.Data.SeekPositionTicks);
|
//because the server sends seek an privious track at same time so i have to do timing
|
||||||
|
setTimeout(async()=>{playbackmanager.seek(data.Data.SeekPositionTicks);},20)
|
||||||
|
} else if (data.Data.Command === "NextTrack") {
|
||||||
|
try {
|
||||||
|
playbackmanager.nextTrack();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
} else if (data.Data.Command === "PreviousTrack") {
|
||||||
|
try{
|
||||||
|
console.log(ticksToSeconds(playbackmanager.getPostitionTicks())<10,ticksToSeconds(playbackmanager.getPostitionTicks()),` (${playbackmanager.getPostitionTicks()})`," < ",10)
|
||||||
|
if(ticksToSeconds(playbackmanager.getPostitionTicks())<10){
|
||||||
|
playbackmanager.previousTrack();
|
||||||
|
}
|
||||||
|
}catch(error){
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user