improve play message

This commit is contained in:
KGT1 2020-09-30 17:27:09 +02:00
parent a218a71ac2
commit 0b76f59077
7 changed files with 182 additions and 48 deletions

View File

@ -42,6 +42,7 @@ docker run -d \
-e JELLYFIN_USERNAME="" \ -e JELLYFIN_USERNAME="" \
-e JELLYFIN_PASSWORD="" \ -e JELLYFIN_PASSWORD="" \
-e JELLYFIN_APP_NAME="Jellyfin Discord Music Bot" \ -e JELLYFIN_APP_NAME="Jellyfin Discord Music Bot" \
-e MESSAGE_UPDATE_INTERVAL="2000" \
--restart unless-stopped \ --restart unless-stopped \
kgt1/jellyfin-discord-music-bot kgt1/jellyfin-discord-music-bot
``` ```

View File

@ -8,6 +8,7 @@ if (!configfile["server-adress"]) { configfile["server-adress"] = process.env.JE
if (!configfile["jellyfin-username"]) { configfile["jellyfin-username"] = process.env.JELLYFIN_USERNAME; } if (!configfile["jellyfin-username"]) { configfile["jellyfin-username"] = process.env.JELLYFIN_USERNAME; }
if (!configfile["jellyfin-password"]) { configfile["jellyfin-password"] = process.env.JELLYFIN_PASSWORD; } if (!configfile["jellyfin-password"]) { configfile["jellyfin-password"] = process.env.JELLYFIN_PASSWORD; }
if (!configfile["jellyfin-app-name"]) { configfile["jellyfin-app-name"] = process.env.JELLYFIN_APP_NAME; } if (!configfile["jellyfin-app-name"]) { configfile["jellyfin-app-name"] = process.env.JELLYFIN_APP_NAME; }
if (!configfile["interactive-seek-bar-update-intervall"]) { configfile["interactive-seek-bar-update-intervall"] = parseInt(process.env.MESSAGE_UPDATE_INTERVAL); }
fs.writeFile(filename, JSON.stringify(configfile, null, 1), (err) => { fs.writeFile(filename, JSON.stringify(configfile, null, 1), (err) => {
if (err) return console.error(err); if (err) return console.error(err);

View File

@ -1,48 +1,81 @@
const discordclientmanager = require("./discordclientmanager"); const discordclientmanager = require("./discordclientmanager");
const CONFIG = require("../config.json");
const {
secondsToHms,
ticksToSeconds
} = require("./util");
// eslint-disable-next-line
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) { string += "█"; } else { string += "▒"; } if (percent > (iX) / NUMBER_OF_CHARS) {
string += "█";
} else {
string += "▒";
}
}
return string;
}
/**
*
* @param {String} string
* @returns {String}
*/
// TODO do this with something like wcwidth
function getMaxWidthString (string) {
const NUMBER_OF_CHARS = 12;
if (string.length > NUMBER_OF_CHARS) {
return string.slice(0, NUMBER_OF_CHARS - 3) + "...";
} }
return string; return string;
} }
class InterActivePlayMessage { class InterActivePlayMessage {
// musicplayermessage // musicplayermessage
// probably should have done events instead of.
/** /**
* *
* @param {Object} message * @param {Object} message
* @param {String} title * @param {String} title
* @param {String} artist * @param {String} artist
* @param {String} imageURL * @param {String} imageURL
* @param {String} itemURL * @param {String} itemURL
* @param {Function} getProgress * @param {Number} ticksLength
* @param {Function} onPrevious * @param {Function} onPrevious
* @param {Function} onPausePlay * @param {Function} onPausePlay
* @param {Function} onStop * @param {Function} onStop
* @param {Function} onNext * @param {Function} onNext
* @param {Function} onRepeat * @param {Function} onRepeat
*/ */
constructor (message, title, artist, imageURL, itemURL, getProgress, onPrevious, onPausePlay, onStop, onNext, onRepeat) { constructor (message, title, artist, imageURL, itemURL, ticksLength, onPrevious, onPausePlay, onStop, onNext, onRepeat, playlistLenth) {
this.ticksLength = ticksLength;
var exampleEmbed = { var exampleEmbed = {
color: 0x0099ff, color: 0x0099ff,
title: "Now Playing", title: "Now Playing",
url: itemURL, url: itemURL,
description: `${title} by ${artist}`, description: `${getMaxWidthString(title)}\nby\n ${getMaxWidthString(artist)}`,
thumbnail: { thumbnail: {
url: imageURL url: imageURL
}, },
/* fields: [{ fields: [],
name: getProgressString(0),
value: `${0}`,
inline: false,
}, ], */
timestamp: new Date() timestamp: new Date()
}; };
if (typeof CONFIG["interactive-seek-bar-update-intervall"] === "number") {
exampleEmbed.fields.push({
name: getProgressString(0 / this.ticksLength),
value: `${secondsToHms(0)} / ${secondsToHms(ticksToSeconds(this.ticksLength))}`,
inline: false
});
}
if (playlistLenth) {
exampleEmbed.fields.push({
name: `1 of ${playlistLenth}`,
value: "Playlist",
inline: false
});
}
message.channel.send({ message.channel.send({
embed: exampleEmbed embed: exampleEmbed
}) })
@ -91,6 +124,37 @@ class InterActivePlayMessage {
}); });
} }
updateProgress (ticks) {
this.musicplayermessage.embeds[0].fields[0] = {
name: getProgressString(ticks / this.ticksLength),
value: `${secondsToHms(ticksToSeconds(ticks))} / ${secondsToHms(ticksToSeconds(this.ticksLength))}`,
inline: false
};
this.musicplayermessage.timestamp = new Date();
this.musicplayermessage.edit(this.musicplayermessage.embeds[0]);
}
updateCurrentSongMessage (title, artist, imageURL, itemURL, ticksLength, playlistIndex, playlistLenth) {
this.musicplayermessage.embeds[0].url = itemURL;
this.musicplayermessage.embeds[0].description = `${getMaxWidthString(title)}\nby\n${getMaxWidthString(artist)}`;
this.musicplayermessage.embeds[0].thumbnail = { url: imageURL };
const indexOfPlaylistMessage = this.musicplayermessage.embeds[0].fields.findIndex((element) => { return element.value === "Playlist"; });
if (indexOfPlaylistMessage === -1) {
this.musicplayermessage.embeds[0].fields.push({
name: `${playlistIndex} of ${playlistLenth}`,
value: "Playlist",
inline: false
});
} else {
this.musicplayermessage.embeds[0].fields[indexOfPlaylistMessage].name = `${playlistIndex} of ${playlistLenth}`;
}
this.ticksLength = ticksLength;
this.musicplayermessage.timestamp = new Date();
this.musicplayermessage.edit(this.musicplayermessage.embeds[0]);
}
destroy () { destroy () {
this.musicplayermessage.delete(); this.musicplayermessage.delete();
delete this; delete this;

View File

@ -1,12 +1,15 @@
const InterActivePlayMessage = require("./InterActivePlayMessage"); const InterActivePlayMessage = require("./InterActivePlayMessage");
const CONFIG = require("../config.json");
var iapm; var iapm;
function init (message, title, artist, imageURL, itemURL, getProgress, onPrevious, onPausePlay, onStop, onNext, onRepeat) { var updateInterval;
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); iapm = new InterActivePlayMessage(message, title, artist, imageURL, itemURL, getProgress, onPrevious, onPausePlay, onStop, onNext, onRepeat, playlistLenth);
} }
function destroy () { function destroy () {
@ -16,6 +19,11 @@ function destroy () {
} else { } else {
throw Error("No Interactive Message Found"); throw Error("No Interactive Message Found");
} }
if (updateInterval !== "undefined") {
clearInterval(updateInterval);
updateInterval = undefined;
}
} }
function hasMessage () { function hasMessage () {
@ -25,9 +33,24 @@ function hasMessage () {
return true; return true;
} }
} }
/**
*
* @param {Function} callback function to retrieve current ticks
*/
function startUpate (callback) {
updateInterval = setInterval(() => {
iapm.updateProgress(callback());
}, CONFIG["interactive-seek-bar-update-intervall"]);
}
function updateCurrentSongMessage (title, artist, imageURL, itemURL, ticksLength, playlistIndex, playlistLenth) {
iapm.updateCurrentSongMessage(title, artist, imageURL, itemURL, ticksLength, playlistIndex, playlistLenth);
}
module.exports = { module.exports = {
init, init,
destroy, destroy,
hasMessage hasMessage,
startUpate,
updateCurrentSongMessage
}; };

View File

@ -5,11 +5,9 @@ const {
} = require("./util"); } = require("./util");
const { const {
hmsToSeconds, hmsToSeconds,
ticksToSeconds,
getDiscordEmbedError getDiscordEmbedError
} = require("./util"); } = require("./util");
const interactivemsghandler = require("./interactivemsghandler");
const discordclientmanager = require("./discordclientmanager"); const discordclientmanager = require("./discordclientmanager");
const jellyfinClientManager = require("./jellyfinclientmanager"); const jellyfinClientManager = require("./jellyfinclientmanager");
const playbackmanager = require("./playbackmanager"); const playbackmanager = require("./playbackmanager");
@ -83,23 +81,6 @@ function summonMessage (message) {
} }
} }
async function songPlayMessage (message, itemId) {
const itemIdDetails = await jellyfinClientManager.getJellyfinClient().getItem(jellyfinClientManager.getJellyfinClient().getCurrentUserId(), itemId);
const imageURL = await jellyfinClientManager.getJellyfinClient().getImageUrl(itemIdDetails.AlbumId, { type: "Primary" });
try {
interactivemsghandler.init(message, itemIdDetails.Name, itemIdDetails.Artists[0] || "VA", imageURL,
`${jellyfinClientManager.getJellyfinClient().serverAddress()}/web/index.html#!/details?id=${itemIdDetails.AlbumId}`,
undefined,
((ticksToSeconds(playbackmanager.getPostitionTicks()) > 10) ? playbackmanager.previousTrack : playbackmanager.seek),
playbackmanager.playPause,
playbackmanager.stop,
playbackmanager.nextTrack,
playbackmanager.setIsRepeat);
} catch (error) {
}
}
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);
@ -120,8 +101,8 @@ async function playThis (message) {
} }
discordClient.user.client.voice.connections.forEach((element) => { discordClient.user.client.voice.connections.forEach((element) => {
songPlayMessage(message, itemID);
playbackmanager.startPlaying(element, [itemID], 0, 0, isSummendByPlay); playbackmanager.startPlaying(element, [itemID], 0, 0, isSummendByPlay);
playbackmanager.spawnPlayMessage(message);
}); });
} }
@ -191,6 +172,15 @@ 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"] + "add")) {
const indexOfArgument = message.content.indexOf(CONFIG["discord-prefix"] + "add") + (CONFIG["discord-prefix"] + "add").length + 1;
const argument = message.content.slice(indexOfArgument);
try {
playbackmanager.addTrack(argument);
} 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()

View File

@ -1,5 +1,6 @@
const interactivemsghandler = require("./interactivemsghandler"); const interactivemsghandler = require("./interactivemsghandler");
const CONFIG = require("../config.json");
const discordclientmanager = require("./discordclientmanager"); const discordclientmanager = require("./discordclientmanager");
const { const {
getAudioDispatcher, getAudioDispatcher,
@ -33,6 +34,7 @@ function startPlaying (voiceconnection = discordclientmanager.getDiscordClient()
currentPlayingPlaylistIndex = playlistIndex; currentPlayingPlaylistIndex = playlistIndex;
_disconnectOnFinish = disconnectOnFinish; _disconnectOnFinish = disconnectOnFinish;
_seek = seekTo * 1000; _seek = seekTo * 1000;
updatePlayMessage();
async function playasync () { async function playasync () {
const url = streamURLbuilder(itemIDPlaylist[playlistIndex], voiceconnection.channel.bitrate); const url = streamURLbuilder(itemIDPlaylist[playlistIndex], voiceconnection.channel.bitrate);
setAudioDispatcher(voiceconnection.play(url, { setAudioDispatcher(voiceconnection.play(url, {
@ -66,6 +68,35 @@ function startPlaying (voiceconnection = discordclientmanager.getDiscordClient()
console.error(rsn); console.error(rsn);
}); });
} }
async function spawnPlayMessage (message) {
const itemIdDetails = await jellyfinClientManager.getJellyfinClient().getItem(jellyfinClientManager.getJellyfinClient().getCurrentUserId(), getItemId());
const imageURL = await jellyfinClientManager.getJellyfinClient().getImageUrl(itemIdDetails.AlbumId, { type: "Primary" });
try {
interactivemsghandler.init(message, itemIdDetails.Name, itemIdDetails.Artists[0] || "VA", imageURL,
`${jellyfinClientManager.getJellyfinClient().serverAddress()}/web/index.html#!/details?id=${itemIdDetails.AlbumId}`,
itemIdDetails.RunTimeTicks,
((ticksToSeconds(getPostitionTicks()) > 10) ? previousTrack : seek),
playPause,
() => { stop(_disconnectOnFinish ? discordclientmanager.getDiscordClient().user.client.voice.connections.first() : undefined); },
nextTrack,
setIsRepeat,
currentPlayingPlaylist.length);
if (typeof CONFIG["interactive-seek-bar-update-intervall"] === "number") {
interactivemsghandler.startUpate(getPostitionTicks);
}
} catch (error) {
console.error(error);
}
}
async function updatePlayMessage () {
const itemIdDetails = await jellyfinClientManager.getJellyfinClient().getItem(jellyfinClientManager.getJellyfinClient().getCurrentUserId(), getItemId());
const imageURL = await jellyfinClientManager.getJellyfinClient().getImageUrl(itemIdDetails.AlbumId, { type: "Primary" });
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);
}
/** /**
* @param {Number} toSeek - where to seek in ticks * @param {Number} toSeek - where to seek in ticks
*/ */
@ -78,6 +109,10 @@ function seek (toSeek = 0) {
} }
} }
function addTrack (itemID) {
currentPlayingPlaylist.push(itemID);
}
function nextTrack () { function nextTrack () {
// console.log(currentPlayingPlaylistIndex + 1, currentPlayingPlaylist.length); // console.log(currentPlayingPlaylistIndex + 1, currentPlayingPlaylist.length);
if (!(currentPlayingPlaylist)) { if (!(currentPlayingPlaylist)) {
@ -117,7 +152,11 @@ function stop (disconnectVoiceConnection, itemId = getItemId()) {
playSessionId: getPlaySessionId() playSessionId: getPlaySessionId()
}); });
if (getAudioDispatcher()) { if (getAudioDispatcher()) {
getAudioDispatcher().destroy(); try {
getAudioDispatcher().destroy();
} catch (error) {
console.error(error);
}
} }
setAudioDispatcher(undefined); setAudioDispatcher(undefined);
} }
@ -246,5 +285,7 @@ module.exports = {
setIsRepeat, setIsRepeat,
nextTrack, nextTrack,
previousTrack, previousTrack,
getPostitionTicks addTrack,
getPostitionTicks,
spawnPlayMessage
}; };

View File

@ -19,6 +19,19 @@ function hmsToSeconds (str) {
return s; return s;
} }
function secondsToHms (totalSeconds) {
const hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600;
const minutes = Math.floor(totalSeconds / 60);
let seconds = Math.floor(totalSeconds % 60);
seconds = seconds < 10 && seconds > 0 ? `0${seconds}` : `${seconds}`;
if (hours > 0) {
return `${hours}:${minutes}:${seconds}`;
} else {
return `${minutes}:${seconds}`;
}
}
function getDiscordEmbedError (e) { function getDiscordEmbedError (e) {
const Discord = require("discord.js"); const Discord = require("discord.js");
return new Discord.MessageEmbed() return new Discord.MessageEmbed()
@ -32,5 +45,6 @@ module.exports = {
checkJellyfinItemIDRegex, checkJellyfinItemIDRegex,
ticksToSeconds, ticksToSeconds,
hmsToSeconds, hmsToSeconds,
getDiscordEmbedError getDiscordEmbedError,
secondsToHms
}; };