Format code using Prettier

This commit is contained in:
Manuel 2022-08-07 16:14:24 +02:00
parent 8ba7ceb7f4
commit 00a66a668f
13 changed files with 3100 additions and 301 deletions

View File

@ -1,10 +0,0 @@
{
"token":"",
"server-address":"",
"jellyfin-username":"",
"jellyfin-password":"",
"discord-prefix":"?",
"jellyfin-app-name":"Jellyfin Discord Music Bot",
"interactive-seek-bar-update-intervall":2000,
"log-level":"info"
}

10
config.json.example Normal file
View File

@ -0,0 +1,10 @@
{
"token": "",
"server-address": "",
"jellyfin-username": "",
"jellyfin-password": "",
"discord-prefix": "?",
"jellyfin-app-name": "Jellyfin Discord Music Bot",
"interactive-seek-bar-update-intervall": 10000,
"log-level": "info"
}

View File

@ -1,16 +1,13 @@
const discordclientmanager = require("./discordclientmanager"); const discordclientmanager = require("./discordclientmanager");
const CONFIG = require("../config.json"); const CONFIG = require("../config.json");
const { const { secondsToHms, ticksToSeconds } = require("./util");
secondsToHms,
ticksToSeconds
} = require("./util");
function getProgressString (percent) { function getProgressString(percent) {
// the min with of the discord window allows for this many chars // the min with of the discord window allows for this many chars
const NUMBER_OF_CHARS = 12; const NUMBER_OF_CHARS = 12;
let string = ""; let string = "";
for (let iX = 0; iX < NUMBER_OF_CHARS; iX++) { for (let iX = 0; iX < NUMBER_OF_CHARS; iX++) {
if (percent > (iX) / NUMBER_OF_CHARS) { if (percent > iX / NUMBER_OF_CHARS) {
string += "█"; string += "█";
} else { } else {
string += "▒"; string += "▒";
@ -24,7 +21,7 @@ function getProgressString (percent) {
* @returns {String} * @returns {String}
*/ */
// TODO do this with something like wcwidth // TODO do this with something like wcwidth
function getMaxWidthString (string) { function getMaxWidthString(string) {
const NUMBER_OF_CHARS = 12; const NUMBER_OF_CHARS = 12;
if (string.length > NUMBER_OF_CHARS) { if (string.length > NUMBER_OF_CHARS) {
return string.slice(0, NUMBER_OF_CHARS - 3) + "..."; return string.slice(0, NUMBER_OF_CHARS - 3) + "...";
@ -49,36 +46,54 @@ class InterActivePlayMessage {
* @param {Function} onNext * @param {Function} onNext
* @param {Function} onRepeat * @param {Function} onRepeat
*/ */
constructor (message, title, artist, imageURL, itemURL, ticksLength, onPrevious, onPausePlay, onStop, onNext, onRepeat, playlistLenth) { constructor(
message,
title,
artist,
imageURL,
itemURL,
ticksLength,
onPrevious,
onPausePlay,
onStop,
onNext,
onRepeat,
playlistLenth
) {
this.ticksLength = ticksLength; this.ticksLength = ticksLength;
var exampleEmbed = { var exampleEmbed = {
color: 0x0099ff, color: 0x0099ff,
title: "Now Playing", title: "Now Playing",
url: itemURL, url: itemURL,
description: `${getMaxWidthString(title)}\nby\n ${getMaxWidthString(artist)}`, description: `\`\`${getMaxWidthString(title)}\`\` by \`\`${getMaxWidthString(
artist
)}\`\``,
thumbnail: { thumbnail: {
url: imageURL url: imageURL,
}, },
fields: [], fields: [],
timestamp: new Date() timestamp: new Date(),
}; };
if (typeof CONFIG["interactive-seek-bar-update-intervall"] === "number") { if (typeof CONFIG["interactive-seek-bar-update-intervall"] === "number") {
exampleEmbed.fields.push({ exampleEmbed.fields.push({
name: getProgressString(0 / this.ticksLength), name: getProgressString(0 / this.ticksLength),
value: `${secondsToHms(0)} / ${secondsToHms(ticksToSeconds(this.ticksLength))}`, value: `${secondsToHms(0)} / ${secondsToHms(
inline: false ticksToSeconds(this.ticksLength)
)}`,
inline: false,
}); });
} }
if (playlistLenth) { if (playlistLenth) {
exampleEmbed.fields.push({ exampleEmbed.fields.push({
name: `1 of ${playlistLenth}`, name: `1 of ${playlistLenth}`,
value: "Playlist", value: "Playlist",
inline: false inline: false,
}); });
} }
message.channel.send({ message.channel
embed: exampleEmbed .send({
}) embed: exampleEmbed,
})
.then((val) => { .then((val) => {
this.musicplayermessage = val; this.musicplayermessage = val;
val.react("⏮️"); val.react("⏮️");
@ -86,50 +101,59 @@ class InterActivePlayMessage {
val.react("⏹️"); val.react("⏹️");
val.react("⏭️"); val.react("⏭️");
val.react("🔁"); val.react("🔁");
}).catch(console.error); })
.catch(console.error);
function reactionchange (reaction, user, musicplayermessage) { function reactionchange(reaction, user, musicplayermessage) {
if (reaction.message.id === musicplayermessage.id && !(user.bot)) { if (reaction.message.id === musicplayermessage.id && !user.bot) {
try { try {
switch (reaction._emoji.name) { switch (reaction._emoji.name) {
case "⏮️": case "⏮️":
onPrevious(); onPrevious();
break; break;
case "⏯️": case "⏯️":
onPausePlay(); onPausePlay();
break; break;
case "⏹️": case "⏹️":
onStop(); onStop();
break; break;
case "⏭️": case "⏭️":
onNext(); onNext();
break; break;
case "🔁": case "🔁":
onRepeat(); onRepeat();
break; break;
default: default:
break; break;
} }
} catch (error) { } catch (error) {}
}
} }
} }
discordclientmanager.getDiscordClient().on("messageReactionAdd", (reaction, user) => { discordclientmanager
reactionchange(reaction, user, this.musicplayermessage); .getDiscordClient()
}); .on("messageReactionAdd", (reaction, user) => {
discordclientmanager.getDiscordClient().on("messageReactionRemove", (reaction, user) => { reactionchange(reaction, user, this.musicplayermessage);
reactionchange(reaction, user, this.musicplayermessage); });
}); discordclientmanager
.getDiscordClient()
.on("messageReactionRemove", (reaction, user) => {
reactionchange(reaction, user, this.musicplayermessage);
});
} }
updateProgress (ticks) { updateProgress(ticks) {
if (typeof this.musicplayermessage !== "undefined" && typeof this.musicplayermessage.embeds[0] !== "undefined" && typeof this.musicplayermessage.embeds[0].fields[0] !== "undefined") { if (
typeof this.musicplayermessage !== "undefined" &&
typeof this.musicplayermessage.embeds[0] !== "undefined" &&
typeof this.musicplayermessage.embeds[0].fields[0] !== "undefined"
) {
this.musicplayermessage.embeds[0].fields[0] = { this.musicplayermessage.embeds[0].fields[0] = {
name: getProgressString(ticks / this.ticksLength), name: getProgressString(ticks / this.ticksLength),
value: `${secondsToHms(ticksToSeconds(ticks))} / ${secondsToHms(ticksToSeconds(this.ticksLength))}`, value: `${secondsToHms(ticksToSeconds(ticks))} / ${secondsToHms(
inline: false ticksToSeconds(this.ticksLength)
)}`,
inline: false,
}; };
this.musicplayermessage.timestamp = new Date(); this.musicplayermessage.timestamp = new Date();
@ -137,19 +161,34 @@ class InterActivePlayMessage {
} }
} }
updateCurrentSongMessage (title, artist, imageURL, itemURL, ticksLength, playlistIndex, playlistLenth) { updateCurrentSongMessage(
title,
artist,
imageURL,
itemURL,
ticksLength,
playlistIndex,
playlistLenth
) {
this.musicplayermessage.embeds[0].url = itemURL; this.musicplayermessage.embeds[0].url = itemURL;
this.musicplayermessage.embeds[0].description = `${getMaxWidthString(title)}\nby\n${getMaxWidthString(artist)}`; this.musicplayermessage.embeds[0].description = `\`\`${getMaxWidthString(
title
)}\`\` by \`\`${getMaxWidthString(artist)}\`\``;
this.musicplayermessage.embeds[0].thumbnail = { url: imageURL }; this.musicplayermessage.embeds[0].thumbnail = { url: imageURL };
const indexOfPlaylistMessage = this.musicplayermessage.embeds[0].fields.findIndex((element) => { return element.value === "Playlist"; }); const indexOfPlaylistMessage =
this.musicplayermessage.embeds[0].fields.findIndex((element) => {
return element.value === "Playlist";
});
if (indexOfPlaylistMessage === -1) { if (indexOfPlaylistMessage === -1) {
this.musicplayermessage.embeds[0].fields.push({ this.musicplayermessage.embeds[0].fields.push({
name: `${playlistIndex} of ${playlistLenth}`, name: `${playlistIndex} of ${playlistLenth}`,
value: "Playlist", value: "Playlist",
inline: false inline: false,
}); });
} else { } else {
this.musicplayermessage.embeds[0].fields[indexOfPlaylistMessage].name = `${playlistIndex} of ${playlistLenth}`; this.musicplayermessage.embeds[0].fields[
indexOfPlaylistMessage
].name = `${playlistIndex} of ${playlistLenth}`;
} }
this.ticksLength = ticksLength; this.ticksLength = ticksLength;
@ -157,7 +196,7 @@ class InterActivePlayMessage {
this.musicplayermessage.edit(this.musicplayermessage.embeds[0]); this.musicplayermessage.edit(this.musicplayermessage.embeds[0]);
} }
destroy () { destroy() {
this.musicplayermessage.delete(); this.musicplayermessage.delete();
delete this; delete this;
} }

View File

@ -2,14 +2,14 @@ const Discord = require("discord.js");
var discordClient; var discordClient;
function init () { function init() {
discordClient = new Discord.Client(); discordClient = new Discord.Client();
} }
function getDiscordClient () { function getDiscordClient() {
return discordClient; return discordClient;
} }
module.exports = { module.exports = {
getDiscordClient, getDiscordClient,
init init,
}; };

View File

@ -1,13 +1,13 @@
var audioDispatcher; var audioDispatcher;
function setAudioDispatcher (par) { function setAudioDispatcher(par) {
audioDispatcher = par; audioDispatcher = par;
} }
function getAudioDispatcher () { function getAudioDispatcher() {
return audioDispatcher; return audioDispatcher;
} }
module.exports = { module.exports = {
setAudioDispatcher, setAudioDispatcher,
getAudioDispatcher getAudioDispatcher,
}; };

View File

@ -1,3 +1,5 @@
const log = require("loglevel");
try { try {
const CONFIG = require("../config.json"); const CONFIG = require("../config.json");
@ -6,10 +8,8 @@ try {
const discordclientmanager = require("./discordclientmanager"); const discordclientmanager = require("./discordclientmanager");
discordclientmanager.init(); discordclientmanager.init();
const discordClient = discordclientmanager.getDiscordClient(); const discordClient = discordclientmanager.getDiscordClient();
const { const { handleChannelMessage } = require("./messagehandler");
handleChannelMessage
} = require("./messagehandler");
const log = require("loglevel");
const prefix = require("loglevel-plugin-prefix"); const prefix = require("loglevel-plugin-prefix");
const chalk = require("chalk"); const chalk = require("chalk");
const colors = { const colors = {
@ -17,7 +17,7 @@ try {
DEBUG: chalk.cyan, DEBUG: chalk.cyan,
INFO: chalk.blue, INFO: chalk.blue,
WARN: chalk.yellow, WARN: chalk.yellow,
ERROR: chalk.red ERROR: chalk.red,
}; };
log.setLevel(CONFIG["log-level"]); log.setLevel(CONFIG["log-level"]);
@ -26,28 +26,39 @@ try {
log.enableAll(); log.enableAll();
prefix.apply(log, { prefix.apply(log, {
format (level, name, timestamp) { format(level, name, timestamp) {
return `${chalk.gray(`[${timestamp}]`)} ${colors[level.toUpperCase()](level)} ${chalk.green(`${name}:`)}`; return `${chalk.gray(`[${timestamp}]`)} ${colors[level.toUpperCase()](
} level
)} ${chalk.green(`${name}:`)}`;
},
}); });
prefix.apply(log.getLogger("critical"), { prefix.apply(log.getLogger("critical"), {
format (level, name, timestamp) { format(level, name, timestamp) {
return chalk.red.bold(`[${timestamp}] ${level} ${name}:`); return chalk.red.bold(`[${timestamp}] ${level} ${name}:`);
} },
}); });
jellyfinClientManager.init(); jellyfinClientManager.init();
// TODO Error Checking as the apiclients is inefficent // TODO Error Checking as the apiclients is inefficent
jellyfinClientManager.getJellyfinClient().authenticateUserByName(CONFIG["jellyfin-username"], CONFIG["jellyfin-password"]).then((response) => { jellyfinClientManager
jellyfinClientManager.getJellyfinClient().setAuthenticationInfo(response.AccessToken, response.SessionInfo.UserId); .getJellyfinClient()
}); .authenticateUserByName(
CONFIG["jellyfin-username"],
CONFIG["jellyfin-password"]
)
.then((response) => {
jellyfinClientManager
.getJellyfinClient()
.setAuthenticationInfo(response.AccessToken, response.SessionInfo.UserId);
});
discordClient.on("message", message => { discordClient.on("message", (message) => {
handleChannelMessage(message); handleChannelMessage(message);
}); });
discordClient.login(CONFIG.token); discordClient.login(CONFIG.token);
} catch (error) { } catch (error) {
log.error(error);
console.error(error); console.error(error);
} }

View File

@ -5,14 +5,40 @@ var iapm;
var updateInterval; var updateInterval;
function init (message, title, artist, imageURL, itemURL, getProgress, onPrevious, onPausePlay, onStop, onNext, onRepeat, playlistLenth) { function init(
message,
title,
artist,
imageURL,
itemURL,
getProgress,
onPrevious,
onPausePlay,
onStop,
onNext,
onRepeat,
playlistLenth
) {
if (typeof iapm !== "undefined") { if (typeof iapm !== "undefined") {
destroy(); destroy();
} }
iapm = new InterActivePlayMessage(message, title, artist, imageURL, itemURL, getProgress, onPrevious, onPausePlay, onStop, onNext, onRepeat, playlistLenth); iapm = new InterActivePlayMessage(
message,
title,
artist,
imageURL,
itemURL,
getProgress,
onPrevious,
onPausePlay,
onStop,
onNext,
onRepeat,
playlistLenth
);
} }
function destroy () { function destroy() {
if (typeof iapm !== "undefined") { if (typeof iapm !== "undefined") {
iapm.destroy(); iapm.destroy();
iapm = undefined; iapm = undefined;
@ -26,7 +52,7 @@ function destroy () {
} }
} }
function hasMessage () { function hasMessage() {
if (typeof iapm === "undefined") { if (typeof iapm === "undefined") {
return false; return false;
} else { } else {
@ -37,17 +63,36 @@ function hasMessage () {
* *
* @param {Function} callback function to retrieve current ticks * @param {Function} callback function to retrieve current ticks
*/ */
function startUpate (callback) { function startUpate(callback) {
if (typeof CONFIG["interactive-seek-bar-update-intervall"] === "number" && CONFIG["interactive-seek-bar-update-intervall"] > 0) { if (
typeof CONFIG["interactive-seek-bar-update-intervall"] === "number" &&
CONFIG["interactive-seek-bar-update-intervall"] > 0
) {
updateInterval = setInterval(() => { updateInterval = setInterval(() => {
iapm.updateProgress(callback()); iapm.updateProgress(callback());
}, CONFIG["interactive-seek-bar-update-intervall"]); }, CONFIG["interactive-seek-bar-update-intervall"]);
} }
} }
function updateCurrentSongMessage (title, artist, imageURL, itemURL, ticksLength, playlistIndex, playlistLenth) { function updateCurrentSongMessage(
title,
artist,
imageURL,
itemURL,
ticksLength,
playlistIndex,
playlistLenth
) {
if (typeof iapm !== "undefined") { if (typeof iapm !== "undefined") {
iapm.updateCurrentSongMessage(title, artist, imageURL, itemURL, ticksLength, playlistIndex, playlistLenth); iapm.updateCurrentSongMessage(
title,
artist,
imageURL,
itemURL,
ticksLength,
playlistIndex,
playlistLenth
);
} else { } else {
throw Error("No Interactive Message Found"); throw Error("No Interactive Message Found");
} }
@ -58,5 +103,5 @@ module.exports = {
destroy, destroy,
hasMessage, hasMessage,
startUpate, startUpate,
updateCurrentSongMessage updateCurrentSongMessage,
}; };

View File

@ -1,24 +1,29 @@
const { ApiClient, Events } = require("jellyfin-apiclient"); const { ApiClient, Events } = require("jellyfin-apiclient");
const CONFIG = require("../config.json"); const CONFIG = require("../config.json");
const os = require("os"); const os = require("os");
var jellyfinClient; var jellyfinClient;
function init () { function init() {
jellyfinClient = new ApiClient(CONFIG["server-address"], CONFIG["jellyfin-app-name"], "0.0.1", os.hostname(), os.hostname()); jellyfinClient = new ApiClient(
CONFIG["server-address"],
CONFIG["jellyfin-app-name"],
"0.0.1",
os.hostname(),
os.hostname()
);
} }
function getJellyfinClient () { function getJellyfinClient() {
return jellyfinClient; return jellyfinClient;
} }
function getJellyfinEvents () { function getJellyfinEvents() {
return Events; return Events;
} }
module.exports = { module.exports = {
getJellyfinClient, getJellyfinClient,
getJellyfinEvents, getJellyfinEvents,
init init,
}; };

View File

@ -1,12 +1,7 @@
const CONFIG = require("../config.json"); const CONFIG = require("../config.json");
const Discord = require("discord.js"); const Discord = require("discord.js");
const { const { checkJellyfinItemIDRegex } = require("./util");
checkJellyfinItemIDRegex const { hmsToSeconds, getDiscordEmbedError } = require("./util");
} = require("./util");
const {
hmsToSeconds,
getDiscordEmbedError
} = require("./util");
const discordclientmanager = require("./discordclientmanager"); const discordclientmanager = require("./discordclientmanager");
const jellyfinClientManager = require("./jellyfinclientmanager"); const jellyfinClientManager = require("./jellyfinclientmanager");
@ -17,10 +12,12 @@ const discordClient = discordclientmanager.getDiscordClient();
var isSummendByPlay = false; var isSummendByPlay = false;
// random Color of the Jellyfin Logo Gradient // random Color of the Jellyfin Logo Gradient
function getRandomDiscordColor () { function getRandomDiscordColor() {
const random = Math.random(); const random = Math.random();
function randomNumber (b, a) { function randomNumber(b, a) {
return Math.floor(random * Math.pow(Math.pow((b - a), 2), 1 / 2)) + (b > a ? a : b); return (
Math.floor(random * Math.pow(Math.pow(b - a, 2), 1 / 2)) + (b > a ? a : b)
);
} }
const GRANDIENT_START = "#AA5CC3"; const GRANDIENT_START = "#AA5CC3";
@ -40,40 +37,53 @@ function getRandomDiscordColor () {
gE = parseInt(gE, 16); gE = parseInt(gE, 16);
bE = parseInt(bE, 16); bE = parseInt(bE, 16);
return ("#" + ("00" + (randomNumber(rS, rE)).toString(16)).substr(-2) + ("00" + (randomNumber(gS, gE)).toString(16)).substr(-2) + ("00" + (randomNumber(bS, bE)).toString(16)).substr(-2)); return (
"#" +
("00" + randomNumber(rS, rE).toString(16)).substr(-2) +
("00" + randomNumber(gS, gE).toString(16)).substr(-2) +
("00" + randomNumber(bS, bE).toString(16)).substr(-2)
);
} }
// Song Search, return the song itemID // Song Search, return the song itemID
async function searchForItemID (searchString) { async function searchForItemID(searchString) {
const response = await jellyfinClientManager.getJellyfinClient().getSearchHints({ const response = await jellyfinClientManager
searchTerm: searchString, .getJellyfinClient()
includeItemTypes: "Audio,MusicAlbum,Playlist" .getSearchHints({
}); searchTerm: searchString,
includeItemTypes: "Audio,MusicAlbum,Playlist",
});
if (response.TotalRecordCount < 1) { if (response.TotalRecordCount < 1) {
throw Error("Found nothing"); throw Error("Found nothing");
} else { } else {
switch (response.SearchHints[0].Type) { switch (response.SearchHints[0].Type) {
case "Audio": case "Audio":
return [response.SearchHints[0].ItemId]; return [response.SearchHints[0].ItemId];
case "Playlist": case "Playlist":
case "MusicAlbum": { case "MusicAlbum": {
const resp = await jellyfinClientManager.getJellyfinClient().getItems(jellyfinClientManager.getJellyfinClient().getCurrentUserId(), { sortBy: "SortName", sortOrder: "Ascending", parentId: response.SearchHints[0].ItemId }); const resp = await jellyfinClientManager
const itemArray = []; .getJellyfinClient()
resp.Items.forEach(element => { .getItems(jellyfinClientManager.getJellyfinClient().getCurrentUserId(), {
itemArray.push(element.Id); sortBy: "SortName",
}); sortOrder: "Ascending",
return itemArray; parentId: response.SearchHints[0].ItemId,
} });
const itemArray = [];
resp.Items.forEach((element) => {
itemArray.push(element.Id);
});
return itemArray;
}
} }
} }
} }
function summon (voiceChannel) { function summon(voiceChannel) {
voiceChannel.join(); voiceChannel.join();
} }
function summonMessage (message) { function summonMessage(message) {
if (!message.member.voice.channel) { if (!message.member.voice.channel) {
message.reply("please join a voice channel to summon me!"); message.reply("please join a voice channel to summon me!");
} else if (message.channel.type === "dm") { } else if (message.channel.type === "dm") {
@ -93,8 +103,11 @@ function summonMessage (message) {
} }
} }
async function playThis (message) { async function playThis(message) {
const indexOfItemID = message.content.indexOf(CONFIG["discord-prefix"] + "play") + (CONFIG["discord-prefix"] + "play").length + 1; const indexOfItemID =
message.content.indexOf(CONFIG["discord-prefix"] + "play") +
(CONFIG["discord-prefix"] + "play").length +
1;
const argument = message.content.slice(indexOfItemID); const argument = message.content.slice(indexOfItemID);
let items; let items;
// check if play command was used with itemID // check if play command was used with itemID
@ -107,17 +120,30 @@ async function playThis (message) {
} catch (e) { } catch (e) {
const noSong = getDiscordEmbedError(e); const noSong = getDiscordEmbedError(e);
message.channel.send(noSong); message.channel.send(noSong);
playbackmanager.stop(isSummendByPlay ? discordClient.user.client.voice.connections.first() : undefined); playbackmanager.stop(
isSummendByPlay
? discordClient.user.client.voice.connections.first()
: undefined,
);
return; return;
} }
} }
playbackmanager.startPlaying(discordClient.user.client.voice.connections.first(), items, 0, 0, isSummendByPlay); playbackmanager.startPlaying(
discordClient.user.client.voice.connections.first(),
items,
0,
0,
isSummendByPlay,
);
playbackmanager.spawnPlayMessage(message); playbackmanager.spawnPlayMessage(message);
} }
async function addThis (message) { async function addThis(message) {
const indexOfItemID = message.content.indexOf(CONFIG["discord-prefix"] + "add") + (CONFIG["discord-prefix"] + "add").length + 1; const indexOfItemID =
message.content.indexOf(CONFIG["discord-prefix"] + "add") +
(CONFIG["discord-prefix"] + "add").length +
1;
const argument = message.content.slice(indexOfItemID); const argument = message.content.slice(indexOfItemID);
let items; let items;
// check if play command was used with itemID // check if play command was used with itemID
@ -137,7 +163,7 @@ async function addThis (message) {
playbackmanager.addTracks(items); playbackmanager.addTracks(items);
} }
function handleChannelMessage (message) { function handleChannelMessage(message) {
getRandomDiscordColor(); getRandomDiscordColor();
if (message.content.startsWith(CONFIG["discord-prefix"] + "summon")) { if (message.content.startsWith(CONFIG["discord-prefix"] + "summon")) {
@ -146,7 +172,9 @@ function handleChannelMessage (message) {
websocketHanler.openSocket(); websocketHanler.openSocket();
summonMessage(message); summonMessage(message);
} else if (message.content.startsWith(CONFIG["discord-prefix"] + "disconnect")) { } else if (
message.content.startsWith(CONFIG["discord-prefix"] + "disconnect")
) {
playbackmanager.stop(); playbackmanager.stop();
jellyfinClientManager.getJellyfinClient().closeWebSocket(); jellyfinClientManager.getJellyfinClient().closeWebSocket();
discordClient.user.client.voice.connections.forEach((element) => { discordClient.user.client.voice.connections.forEach((element) => {
@ -160,7 +188,10 @@ function handleChannelMessage (message) {
.setTimestamp() .setTimestamp()
.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")
) {
try { try {
playbackmanager.playPause(); playbackmanager.playPause();
const noPlay = new Discord.MessageEmbed() const noPlay = new Discord.MessageEmbed()
@ -188,7 +219,10 @@ function handleChannelMessage (message) {
playbackmanager.stop(); playbackmanager.stop();
} }
} else if (message.content.startsWith(CONFIG["discord-prefix"] + "seek")) { } else if (message.content.startsWith(CONFIG["discord-prefix"] + "seek")) {
const indexOfArgument = message.content.indexOf(CONFIG["discord-prefix"] + "seek") + (CONFIG["discord-prefix"] + "seek").length + 1; const indexOfArgument =
message.content.indexOf(CONFIG["discord-prefix"] + "seek") +
(CONFIG["discord-prefix"] + "seek").length +
1;
const argument = message.content.slice(indexOfArgument); const argument = message.content.slice(indexOfArgument);
try { try {
playbackmanager.seek(hmsToSeconds(argument) * 10000000); playbackmanager.seek(hmsToSeconds(argument) * 10000000);
@ -216,43 +250,59 @@ function handleChannelMessage (message) {
/* eslint-disable quotes */ /* eslint-disable quotes */
const reply = new Discord.MessageEmbed() const reply = new Discord.MessageEmbed()
.setColor(getRandomDiscordColor()) .setColor(getRandomDiscordColor())
.setTitle("<:musical_note:757938541123862638> " + "Jellyfin Discord Music Bot" + " <:musical_note:757938541123862638> ") .setTitle(
.addFields({ "<:musical_note:757938541123862638> " +
name: `${CONFIG["discord-prefix"]}summon`, "Jellyfin Discord Music Bot" +
value: "Join the channel the author of the message" " <:musical_note:757938541123862638> ",
}, { )
name: `${CONFIG["discord-prefix"]}disconnect`, .addFields(
value: "Disconnect from all current Voice Channels" {
}, { name: `${CONFIG["discord-prefix"]}summon`,
name: `${CONFIG["discord-prefix"]}play`, value: "Join the channel the author of the message",
value: "Play the following item" },
}, { {
name: `${CONFIG["discord-prefix"]}add`, name: `${CONFIG["discord-prefix"]}disconnect`,
value: "Add the following item to the current playlist" value: "Disconnect from all current Voice Channels",
}, { },
name: `${CONFIG["discord-prefix"]}pause/resume`, {
value: "Pause/Resume audio" name: `${CONFIG["discord-prefix"]}play`,
}, { value: "Play the following item",
name: `${CONFIG["discord-prefix"]}seek`, },
value: "Where to Seek to in seconds or MM:SS" {
}, { name: `${CONFIG["discord-prefix"]}add`,
name: `${CONFIG["discord-prefix"]}skip`, value: "Add the following item to the current playlist",
value: "Skip this Song" },
}, { {
name: `${CONFIG["discord-prefix"]}spawn`, name: `${CONFIG["discord-prefix"]}pause/resume`,
value: "Spawns an Interactive Play Controller" value: "Pause/Resume audio",
}, { },
name: `${CONFIG["discord-prefix"]}help`, {
value: "Display this help message" name: `${CONFIG["discord-prefix"]}seek`,
}, { value: "Where to Seek to in seconds or MM:SS",
name: `GitHub`, },
value: "Find the code for this bot at: https://github.com/KGT1/jellyfin-discord-music-bot" {
}); name: `${CONFIG["discord-prefix"]}skip`,
value: "Skip this Song",
},
{
name: `${CONFIG["discord-prefix"]}spawn`,
value: "Spawns an Interactive Play Controller",
},
{
name: `${CONFIG["discord-prefix"]}help`,
value: "Display this help message",
},
{
name: `GitHub`,
value:
"Find the code for this bot at: https://github.com/KGT1/jellyfin-discord-music-bot",
},
);
message.channel.send(reply); message.channel.send(reply);
/* eslint-enable quotes */ /* eslint-enable quotes */
} }
} }
module.exports = { module.exports = {
handleChannelMessage handleChannelMessage,
}; };

View File

@ -1,4 +1,3 @@
const interactivemsghandler = require("./interactivemsghandler"); const interactivemsghandler = require("./interactivemsghandler");
const CONFIG = require("../config.json"); const CONFIG = require("../config.json");
const discordclientmanager = require("./discordclientmanager"); const discordclientmanager = require("./discordclientmanager");
@ -6,11 +5,9 @@ const log = require("loglevel");
const { const {
getAudioDispatcher, getAudioDispatcher,
setAudioDispatcher setAudioDispatcher,
} = require("./dispachermanager"); } = require("./dispachermanager");
const { const { ticksToSeconds } = require("./util");
ticksToSeconds
} = require("./util");
// this whole thing should be a class but its probably too late now. // this whole thing should be a class but its probably too late now.
@ -23,42 +20,77 @@ 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.(doesnt yet work i dont know why) // so the server transcodes. Seems appropriate as it has the source file.(doesnt yet work i dont know why)
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(), itemIDPlaylist = currentPlayingPlaylist, playlistIndex = currentPlayingPlaylistIndex, seekTo, disconnectOnFinish = _disconnectOnFinish) { function startPlaying(
log.debug("start playing ", playlistIndex, ". of list: ", itemIDPlaylist, " in a voiceconnection?: ", typeof voiceconnection !== "undefined"); voiceconnection = discordclientmanager
.getDiscordClient()
.user.client.voice.connections.first(),
itemIDPlaylist = currentPlayingPlaylist,
playlistIndex = currentPlayingPlaylistIndex,
seekTo,
disconnectOnFinish = _disconnectOnFinish
) {
log.debug(
"start playing ",
playlistIndex,
". of list: ",
itemIDPlaylist,
" in a voiceconnection?: ",
typeof voiceconnection !== "undefined"
);
isPaused = false; isPaused = false;
currentPlayingPlaylist = itemIDPlaylist; currentPlayingPlaylist = itemIDPlaylist;
currentPlayingPlaylistIndex = playlistIndex; currentPlayingPlaylistIndex = playlistIndex;
_disconnectOnFinish = disconnectOnFinish; _disconnectOnFinish = disconnectOnFinish;
_seek = seekTo * 1000; _seek = seekTo * 1000;
updatePlayMessage(); updatePlayMessage();
async function playasync () { async function playasync() {
const url = streamURLbuilder(itemIDPlaylist[playlistIndex], voiceconnection.channel.bitrate); const url = streamURLbuilder(
setAudioDispatcher(voiceconnection.play(url, { itemIDPlaylist[playlistIndex],
seek: seekTo voiceconnection.channel.bitrate
})); );
setAudioDispatcher(
voiceconnection.play(url, {
seek: seekTo,
})
);
if (seekTo) { if (seekTo) {
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload()); jellyfinClientManager
.getJellyfinClient()
.reportPlaybackProgress(getProgressPayload());
} else { } else {
jellyfinClientManager.getJellyfinClient().reportPlaybackStart({ jellyfinClientManager.getJellyfinClient().reportPlaybackStart({
userID: `${jellyfinClientManager.getJellyfinClient().getCurrentUserId()}`, userID: `${jellyfinClientManager.getJellyfinClient().getCurrentUserId()}`,
itemID: `${itemIDPlaylist[playlistIndex]}`, itemID: `${itemIDPlaylist[playlistIndex]}`,
canSeek: true, canSeek: true,
playSessionId: getPlaySessionId(), playSessionId: getPlaySessionId(),
playMethod: getPlayMethod() playMethod: getPlayMethod(),
}); });
} }
getAudioDispatcher().on("finish", () => { getAudioDispatcher().on("finish", () => {
if (isRepeat) { if (isRepeat) {
log.debug("repeat and sending following payload as reportPlaybackStopped to the server: ", getStopPayload()); log.debug(
jellyfinClientManager.getJellyfinClient().reportPlaybackStopped(getStopPayload()); "repeat and sending following payload as reportPlaybackStopped to the server: ",
getStopPayload()
);
jellyfinClientManager
.getJellyfinClient()
.reportPlaybackStopped(getStopPayload());
startPlaying(voiceconnection, undefined, currentPlayingPlaylistIndex, 0); startPlaying(voiceconnection, undefined, currentPlayingPlaylistIndex, 0);
} else { } else {
if (currentPlayingPlaylist.length < playlistIndex) { if (currentPlayingPlaylist.length < playlistIndex) {
@ -68,9 +100,19 @@ function startPlaying (voiceconnection = discordclientmanager.getDiscordClient()
stop(undefined, currentPlayingPlaylist[playlistIndex - 1]); stop(undefined, currentPlayingPlaylist[playlistIndex - 1]);
} }
} else { } else {
log.debug("repeat and sending following payload as reportPlaybackStopped to the server: ", getStopPayload()); log.debug(
jellyfinClientManager.getJellyfinClient().reportPlaybackStopped(getStopPayload()); "repeat and sending following payload as reportPlaybackStopped to the server: ",
startPlaying(voiceconnection, undefined, currentPlayingPlaylistIndex + 1, 0); getStopPayload()
);
jellyfinClientManager
.getJellyfinClient()
.reportPlaybackStopped(getStopPayload());
startPlaying(
voiceconnection,
undefined,
currentPlayingPlaylistIndex + 1,
0
);
} }
} }
}); });
@ -80,20 +122,44 @@ function startPlaying (voiceconnection = discordclientmanager.getDiscordClient()
}); });
} }
async function spawnPlayMessage (message) { async function spawnPlayMessage(message) {
log.debug("spawned Play Message?: ", typeof message !== "undefined"); log.debug("spawned Play Message?: ", typeof message !== "undefined");
const itemIdDetails = await jellyfinClientManager.getJellyfinClient().getItem(jellyfinClientManager.getJellyfinClient().getCurrentUserId(), getItemId()); const itemIdDetails = await jellyfinClientManager
const imageURL = await jellyfinClientManager.getJellyfinClient().getImageUrl(itemIdDetails.AlbumId || getItemId(), { type: "Primary" }); .getJellyfinClient()
.getItem(
jellyfinClientManager.getJellyfinClient().getCurrentUserId(),
getItemId()
);
const imageURL = await jellyfinClientManager
.getJellyfinClient()
.getImageUrl(itemIdDetails.AlbumId || getItemId(), { type: "Primary" });
try { try {
interactivemsghandler.init(message, itemIdDetails.Name, itemIdDetails.Artists[0] || "VA", imageURL, interactivemsghandler.init(
`${jellyfinClientManager.getJellyfinClient().serverAddress()}/web/index.html#!/details?id=${itemIdDetails.AlbumId}`, message,
itemIdDetails.Name,
itemIdDetails.Artists[0] || "VA",
imageURL,
`${jellyfinClientManager
.getJellyfinClient()
.serverAddress()}/web/index.html#!/details?id=${itemIdDetails.AlbumId}`,
itemIdDetails.RunTimeTicks, itemIdDetails.RunTimeTicks,
((ticksToSeconds(getPostitionTicks()) > 10) ? previousTrack : seek), ticksToSeconds(getPostitionTicks()) > 10 ? previousTrack : seek,
playPause, playPause,
() => { stop(_disconnectOnFinish ? discordclientmanager.getDiscordClient().user.client.voice.connections.first() : undefined); }, () => {
stop(
_disconnectOnFinish
? discordclientmanager
.getDiscordClient()
.user.client.voice.connections.first()
: undefined
);
},
nextTrack, nextTrack,
() => { setIsRepeat(!isRepeat); }, () => {
currentPlayingPlaylist.length); setIsRepeat(!isRepeat);
},
currentPlayingPlaylist.length
);
if (typeof CONFIG["interactive-seek-bar-update-intervall"] === "number") { if (typeof CONFIG["interactive-seek-bar-update-intervall"] === "number") {
interactivemsghandler.startUpate(getPostitionTicks); interactivemsghandler.startUpate(getPostitionTicks);
} }
@ -102,23 +168,52 @@ async function spawnPlayMessage (message) {
} }
} }
async function updatePlayMessage () { async function updatePlayMessage() {
if (getItemId() !== undefined) { if (getItemId() !== undefined) {
const itemIdDetails = await jellyfinClientManager.getJellyfinClient().getItem(jellyfinClientManager.getJellyfinClient().getCurrentUserId(), getItemId()); const itemIdDetails = await jellyfinClientManager
const imageURL = await jellyfinClientManager.getJellyfinClient().getImageUrl(itemIdDetails.AlbumId || getItemId(), { type: "Primary" }); .getJellyfinClient()
interactivemsghandler.updateCurrentSongMessage(itemIdDetails.Name, itemIdDetails.Artists[0] || "VA", imageURL, .getItem(
`${jellyfinClientManager.getJellyfinClient().serverAddress()}/web/index.html#!/details?id=${itemIdDetails.AlbumId}`, itemIdDetails.RunTimeTicks, currentPlayingPlaylistIndex + 1, currentPlayingPlaylist.length); jellyfinClientManager.getJellyfinClient().getCurrentUserId(),
getItemId()
);
const imageURL = await jellyfinClientManager
.getJellyfinClient()
.getImageUrl(itemIdDetails.AlbumId || getItemId(), { type: "Primary" });
try {
interactivemsghandler.updateCurrentSongMessage(
itemIdDetails.Name,
itemIdDetails.Artists[0] || "VA",
imageURL,
`${jellyfinClientManager
.getJellyfinClient()
.serverAddress()}/web/index.html#!/details?id=${itemIdDetails.AlbumId}`,
itemIdDetails.RunTimeTicks,
currentPlayingPlaylistIndex + 1,
currentPlayingPlaylist.length
);
} catch (exception) {
console.error(exception);
}
} }
} }
/** /**
* @param {Number} toSeek - where to seek in ticks * @param {Number} toSeek - where to seek in ticks
*/ */
function seek (toSeek = 0) { function seek(toSeek = 0) {
log.debug("seek to: ", toSeek); log.debug("seek to: ", toSeek);
if (getAudioDispatcher()) { if (getAudioDispatcher()) {
startPlaying(undefined, undefined, undefined, ticksToSeconds(toSeek), _disconnectOnFinish); startPlaying(
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload()); undefined,
undefined,
undefined,
ticksToSeconds(toSeek),
_disconnectOnFinish
);
jellyfinClientManager
.getJellyfinClient()
.reportPlaybackProgress(getProgressPayload());
} else { } else {
throw Error("No Song Playing"); throw Error("No Song Playing");
} }
@ -127,46 +222,74 @@ function seek (toSeek = 0) {
* *
* @param {Array} itemID - array of itemIDs to be added * @param {Array} itemID - array of itemIDs to be added
*/ */
function addTracks (itemID) { function addTracks(itemID) {
log.debug("added track: ", itemID); log.debug("added track: ", itemID);
currentPlayingPlaylist = currentPlayingPlaylist.concat(itemID); currentPlayingPlaylist = currentPlayingPlaylist.concat(itemID);
} }
function nextTrack () { function nextTrack() {
log.debug("nextTrack"); log.debug("nextTrack");
if (!(currentPlayingPlaylist)) { if (!currentPlayingPlaylist) {
throw Error("There is currently nothing playing"); throw Error("There is currently nothing playing");
} else if (currentPlayingPlaylistIndex + 1 >= currentPlayingPlaylist.length) { } else if (currentPlayingPlaylistIndex + 1 >= currentPlayingPlaylist.length) {
throw Error("This is the Last song"); throw Error("This is the Last song");
} }
log.debug("sending following payload as reportPlaybackStopped to the server: ", getStopPayload()); log.debug(
jellyfinClientManager.getJellyfinClient().reportPlaybackStopped(getStopPayload()); "sending following payload as reportPlaybackStopped to the server: ",
getStopPayload()
);
jellyfinClientManager
.getJellyfinClient()
.reportPlaybackStopped(getStopPayload());
startPlaying(undefined, undefined, currentPlayingPlaylistIndex + 1, 0, _disconnectOnFinish); startPlaying(
undefined,
undefined,
currentPlayingPlaylistIndex + 1,
0,
_disconnectOnFinish
);
} }
function previousTrack () { function previousTrack() {
log.debug("previousTrack"); log.debug("previousTrack");
if (ticksToSeconds(getPostitionTicks()) < 10) { if (ticksToSeconds(getPostitionTicks()) < 10) {
if (!(currentPlayingPlaylist)) { if (!currentPlayingPlaylist) {
throw Error("There is currently nothing playing"); throw Error("There is currently nothing playing");
} else if (currentPlayingPlaylistIndex - 1 < 0) { } else if (currentPlayingPlaylistIndex - 1 < 0) {
startPlaying(undefined, undefined, currentPlayingPlaylistIndex, 0, _disconnectOnFinish); startPlaying(
undefined,
undefined,
currentPlayingPlaylistIndex,
0,
_disconnectOnFinish
);
throw Error("This is the First song"); throw Error("This is the First song");
} }
log.debug("sending following payload as reportPlaybackStopped to the server: ", getStopPayload()); log.debug(
jellyfinClientManager.getJellyfinClient().reportPlaybackStopped(getStopPayload()); "sending following payload as reportPlaybackStopped to the server: ",
getStopPayload()
);
jellyfinClientManager
.getJellyfinClient()
.reportPlaybackStopped(getStopPayload());
startPlaying(undefined, undefined, currentPlayingPlaylistIndex - 1, 0, _disconnectOnFinish); 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, itemId = getItemId()) { function stop(disconnectVoiceConnection, itemId = getItemId()) {
isPaused = true; isPaused = true;
if (interactivemsghandler.hasMessage()) { if (interactivemsghandler.hasMessage()) {
interactivemsghandler.destroy(); interactivemsghandler.destroy();
@ -174,8 +297,13 @@ function stop (disconnectVoiceConnection, itemId = getItemId()) {
if (disconnectVoiceConnection) { if (disconnectVoiceConnection) {
disconnectVoiceConnection.disconnect(); disconnectVoiceConnection.disconnect();
} }
log.debug("stop playback and send following payload as reportPlaybackStopped to the server: ", getStopPayload()); log.debug(
jellyfinClientManager.getJellyfinClient().reportPlaybackStopped(getStopPayload()); "stop playback and send following payload as reportPlaybackStopped to the server: ",
getStopPayload()
);
jellyfinClientManager
.getJellyfinClient()
.reportPlaybackStopped(getStopPayload());
if (getAudioDispatcher()) { if (getAudioDispatcher()) {
try { try {
getAudioDispatcher().destroy(); getAudioDispatcher().destroy();
@ -186,22 +314,26 @@ function stop (disconnectVoiceConnection, itemId = getItemId()) {
setAudioDispatcher(undefined); setAudioDispatcher(undefined);
} }
function pause () { function pause() {
log.debug("pause"); log.debug("pause");
isPaused = true; isPaused = true;
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload()); jellyfinClientManager
.getJellyfinClient()
.reportPlaybackProgress(getProgressPayload());
getAudioDispatcher().pause(true); getAudioDispatcher().pause(true);
} }
function resume () { function resume() {
log.debug("resume"); log.debug("resume");
isPaused = false; isPaused = false;
jellyfinClientManager.getJellyfinClient().reportPlaybackProgress(getProgressPayload()); jellyfinClientManager
.getJellyfinClient()
.reportPlaybackProgress(getProgressPayload());
getAudioDispatcher().resume(); getAudioDispatcher().resume();
} }
function playPause () { function playPause() {
if (!(getAudioDispatcher())) { if (!getAudioDispatcher()) {
throw Error("There is nothing Playing right now!"); throw Error("There is nothing Playing right now!");
} }
if (getAudioDispatcher().paused) { if (getAudioDispatcher().paused) {
@ -211,17 +343,20 @@ function playPause () {
} }
} }
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
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 "DirectPlay"; return "DirectPlay";
} }
function getRepeatMode () { function getRepeatMode() {
if (isRepeat) { if (isRepeat) {
return "RepeatOne"; return "RepeatOne";
} else { } else {
@ -229,43 +364,45 @@ function getRepeatMode () {
} }
} }
function getPlaylistItemId () { function getPlaylistItemId() {
return getItemId(); return getItemId();
} }
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: getItemId(), {
// as I curently dont support Playlists Id: getItemId(),
PlaylistItemId: getPlaylistItemId() // as I curently dont support Playlists
}]; 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() {
if (typeof currentPlayingPlaylist !== "undefined") { if (typeof currentPlayingPlaylist !== "undefined") {
return currentPlayingPlaylist[currentPlayingPlaylistIndex]; return currentPlayingPlaylist[currentPlayingPlaylistIndex];
} }
return undefined; return undefined;
} }
function getIsPaused () { function getIsPaused() {
// AudioDispacker Paused is to slow // AudioDispacker Paused is to slow
if (isPaused === undefined) { if (isPaused === undefined) {
@ -275,7 +412,7 @@ function getIsPaused () {
return isPaused; return isPaused;
} }
function setIsRepeat (arg) { function setIsRepeat(arg) {
if (arg === undefined) { if (arg === undefined) {
if (!(isRepeat === undefined)) { if (!(isRepeat === undefined)) {
isRepeat = !isRepeat; isRepeat = !isRepeat;
@ -284,7 +421,7 @@ function setIsRepeat (arg) {
isRepeat = arg; isRepeat = arg;
} }
function getProgressPayload () { function getProgressPayload() {
const payload = { const payload = {
CanSeek: getCanSeek(), CanSeek: getCanSeek(),
IsMuted: getIsMuted(), IsMuted: getIsMuted(),
@ -298,18 +435,18 @@ function getProgressPayload () {
PositionTicks: getPostitionTicks(), PositionTicks: getPostitionTicks(),
RepeatMode: getRepeatMode(), RepeatMode: getRepeatMode(),
VolumeLevel: getVolumeLevel(), VolumeLevel: getVolumeLevel(),
EventName: "pauseplayupdate" EventName: "pauseplayupdate",
}; };
return payload; return payload;
} }
function getStopPayload () { function getStopPayload() {
const payload = { const payload = {
userId: jellyfinClientManager.getJellyfinClient().getCurrentUserId(), userId: jellyfinClientManager.getJellyfinClient().getCurrentUserId(),
itemId: getItemId(), itemId: getItemId(),
sessionID: getPlaySessionId(), sessionID: getPlaySessionId(),
playSessionId: getPlaySessionId(), playSessionId: getPlaySessionId(),
positionTicks: getPostitionTicks() positionTicks: getPostitionTicks(),
}; };
return payload; return payload;
} }
@ -326,5 +463,5 @@ module.exports = {
previousTrack, previousTrack,
addTracks, addTracks,
getPostitionTicks, getPostitionTicks,
spawnPlayMessage spawnPlayMessage,
}; };

View File

@ -1,15 +1,20 @@
function checkJellyfinItemIDRegex (strgintomatch) { function checkJellyfinItemIDRegex(strgintomatch) {
const regexresult = strgintomatch.match(/([0-9]|[a-f]){32}/); const regexresult = strgintomatch.match(/([0-9]|[a-f]){32}/);
if (regexresult) { return [regexresult[0]]; } else { return undefined; } if (regexresult) {
return [regexresult[0]];
} else {
return undefined;
}
} }
function ticksToSeconds (ticks) { function ticksToSeconds(ticks) {
return ticks / 10000000; return ticks / 10000000;
} }
function hmsToSeconds (str) { function hmsToSeconds(str) {
var p = str.split(":"); var p = str.split(":");
var s = 0; var m = 1; var s = 0;
var m = 1;
while (p.length > 0) { while (p.length > 0) {
s += m * parseInt(p.pop(), 10); s += m * parseInt(p.pop(), 10);
@ -19,7 +24,7 @@ function hmsToSeconds (str) {
return s; return s;
} }
function secondsToHms (totalSeconds) { function secondsToHms(totalSeconds) {
const hours = Math.floor(totalSeconds / 3600); const hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600; totalSeconds %= 3600;
const minutes = Math.floor(totalSeconds / 60); const minutes = Math.floor(totalSeconds / 60);
@ -32,7 +37,7 @@ function secondsToHms (totalSeconds) {
} }
} }
function getDiscordEmbedError (e) { function getDiscordEmbedError(e) {
const Discord = require("discord.js"); const Discord = require("discord.js");
return new Discord.MessageEmbed() return new Discord.MessageEmbed()
.setColor(0xff0000) .setColor(0xff0000)
@ -46,5 +51,5 @@ module.exports = {
ticksToSeconds, ticksToSeconds,
hmsToSeconds, hmsToSeconds,
getDiscordEmbedError, getDiscordEmbedError,
secondsToHms secondsToHms,
}; };

View File

@ -2,47 +2,55 @@ const jellyfinClientManager = require("./jellyfinclientmanager");
const playbackmanager = require("./playbackmanager"); const playbackmanager = require("./playbackmanager");
const { ticksToSeconds } = require("./util"); const { ticksToSeconds } = require("./util");
function openSocket () { function openSocket() {
jellyfinClientManager.getJellyfinClient().openWebSocket(); jellyfinClientManager.getJellyfinClient().openWebSocket();
jellyfinClientManager.getJellyfinClient().reportCapabilities( jellyfinClientManager.getJellyfinClient().reportCapabilities({
{ PlayableMediaTypes: "Audio",
PlayableMediaTypes: "Audio", SupportsMediaControl: true,
SupportsMediaControl: true, SupportedCommands: "SetRepeatMode,Play,Playstate",
SupportedCommands: "SetRepeatMode,Play,Playstate"
}
);
jellyfinClientManager.getJellyfinEvents().on(jellyfinClientManager.getJellyfinClient(), "message", (type, data) => {
if (data.MessageType === "Play") {
if (data.Data.PlayCommand === "PlayNow") {
playbackmanager.startPlaying(undefined, data.Data.ItemIds, data.Data.StartIndex || 0, 0, false);
}
} else if (data.MessageType === "Playstate") {
if (data.Data.Command === "PlayPause") {
playbackmanager.playPause();
} else if (data.Data.Command === "Stop") {
playbackmanager.stop();
} else if (data.Data.Command === "Seek") {
// 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 {
if (ticksToSeconds(playbackmanager.getPostitionTicks()) < 10) {
playbackmanager.previousTrack();
}
} catch (error) {
console.error(error);
}
}
}
}); });
jellyfinClientManager
.getJellyfinEvents()
.on(jellyfinClientManager.getJellyfinClient(), "message", (type, data) => {
if (data.MessageType === "Play") {
if (data.Data.PlayCommand === "PlayNow") {
playbackmanager.startPlaying(
undefined,
data.Data.ItemIds,
data.Data.StartIndex || 0,
0,
false
);
}
} else if (data.MessageType === "Playstate") {
if (data.Data.Command === "PlayPause") {
playbackmanager.playPause();
} else if (data.Data.Command === "Stop") {
playbackmanager.stop();
} else if (data.Data.Command === "Seek") {
// 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 {
if (ticksToSeconds(playbackmanager.getPostitionTicks()) < 10) {
playbackmanager.previousTrack();
}
} catch (error) {
console.error(error);
}
}
}
});
} }
module.exports = { module.exports = {
openSocket openSocket,
}; };

2499
yarn.lock Normal file

File diff suppressed because it is too large Load Diff