Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .gitmodules
Empty file.
127 changes: 65 additions & 62 deletions DiscordBee.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
namespace MusicBeePlugin
{
using DiscordRPC;
using MusicBeePlugin.DiscordTools;
using MusicBeePlugin.DiscordTools.Assets;
using MusicBeePlugin.DiscordTools.Assets.Uploader;
using MusicBeePlugin.UI;
using DiscordTools;
using DiscordTools.Assets;
using DiscordTools.Assets.Uploader;
using UI;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -69,7 +70,7 @@ public PluginInfo Initialise(IntPtr apiInterfacePtr)
_about.TargetApplication = ""; // current only applies to artwork, lyrics or instant messenger name that appears in the provider drop down selector or target Instant Messenger
_about.Type = PluginType.General;
_about.VersionMajor = 3; // your plugin version
_about.VersionMinor = 1;
_about.VersionMinor = 2;
_about.Revision = 0;
_about.MinInterfaceVersion = MinInterfaceVersion;
_about.MinApiRevision = MinApiRevision;
Expand All @@ -79,7 +80,7 @@ public PluginInfo Initialise(IntPtr apiInterfacePtr)
var workingDir = _mbApiInterface.Setting_GetPersistentStoragePath() + _about.Name;
var settingsFilePath = $"{workingDir}\\{_about.Name}.settings";
_imgurAssetCachePath = $"{workingDir}\\{_about.Name}-Imgur.cache";
_imgurAlbum = $"{workingDir}\\{_about.Name}-Imgur.album";
_imgurAlbum = $"{workingDir}\\{_about.Name}-FreeImageHost.album";

_settings = Settings.GetInstance(settingsFilePath);
_settings.SettingChanged += SettingChangedCallback;
Expand Down Expand Up @@ -190,6 +191,7 @@ public void ReceiveNotification(string _, NotificationType type)
switch (type)
{
case NotificationType.PluginStartup:
case NotificationType.NowPlayingArtworkReady:
var playState = _mbApiInterface.Player_GetPlayState();
// assuming MusicBee wasn't closed and started again in the same Discord session
if (_settings.UpdatePresenceWhenStopped || (playState != PlayState.Paused && playState != PlayState.Stopped))
Expand Down Expand Up @@ -251,24 +253,23 @@ private void UpdateDiscordPresence(PlayState playerGetPlayState)
RichPresence _discordPresence = new RichPresence
{
Assets = new Assets(),
Party = new Party(),
Timestamps = new Timestamps()
Type = ActivityType.Listening
};

// Discord allows only strings with a min length of 2 or the update fails
// so add some exotic space (Mongolian vowel separator) to the string if it is smaller
// Discord also disallows strings bigger than 128bytes so handle that as well
string padString(string input)
string padString(string input, int maxLength = 128)
{
if (!string.IsNullOrEmpty(input))
{
if (input.Length < 2)
{
return input + "\u180E";
}
if (Encoding.UTF8.GetBytes(input).Length > 128)
if (Encoding.UTF8.GetBytes(input).Length > maxLength)
{
byte[] buffer = new byte[128];
byte[] buffer = new byte[maxLength];
char[] inputChars = input.ToCharArray();
Encoding.UTF8.GetEncoder().Convert(
chars: inputChars,
Expand All @@ -288,23 +289,38 @@ string padString(string input)
}

// Button Functionality
if (_settings.ShowButton)
bool tryCreateButton(string label, string uriValue, out Button button)
{
var uri = _layoutHandler.RenderUrl(_settings.ButtonUrl, metaDataDict, '\\');
Debug.WriteLine($"Url: {uri}");

// Validate the URL again.
if (ValidationHelpers.ValidateUri(uri))
var uri = _layoutHandler.RenderUrl(uriValue, metaDataDict, '\\');
if (ValidationHelpers.ValidateUri(uriValue) && !string.IsNullOrEmpty(label))
{
_discordPresence.Buttons = new Button[]
button = new Button
{
new Button
{
Label = padString(_settings.ButtonLabel),
Url = uri
}
Label = padString(label, 32),
Url = uri
};

return true;
}

button = null;
return false;
}

var buttons = new List<Button>();
if (_settings.Button1Enabled && tryCreateButton(_settings.ButtonLabel, _settings.ButtonUrl, out var button1))
{
buttons.Add(button1);
}

if (_settings.Button2Enabled && tryCreateButton(_settings.ButtonLabel2, _settings.ButtonUrl2, out var button2))
{
buttons.Add(button2);
}

if (buttons.Any())
{
_discordPresence.Buttons = buttons.ToArray();
}

void SetImage(string name, bool forceHideSmallImage = false)
Expand Down Expand Up @@ -336,38 +352,37 @@ void SetImage(string name, bool forceHideSmallImage = false)

_discordPresence.State = padString(_layoutHandler.Render(_settings.PresenceState, metaDataDict, _settings.Separator));

var t = DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1));
long t = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

if (_settings.ShowTime)
if (_settings.ShowTime && playerGetPlayState == PlayState.Playing)
{
if (_settings.ShowRemainingTime)
int playerPosition = _mbApiInterface.Player_GetPosition();
int duration = _mbApiInterface.NowPlaying_GetDuration();

_discordPresence.Timestamps = new Timestamps
{
// show remaining time
// subtract current track position from total duration for position seeking
var totalRemainingDuration = _mbApiInterface.NowPlaying_GetDuration() - _mbApiInterface.Player_GetPosition();
_discordPresence.Timestamps.EndUnixMilliseconds = (ulong)(Math.Round(t.TotalSeconds) + Math.Round(totalRemainingDuration / 1000.0));
}
else
StartUnixMilliseconds = (ulong)(t - playerPosition),
EndUnixMilliseconds = (ulong)(t + duration - playerPosition)
};

// Listening to radio will have its duration set to -1. In this case, don't use
// the progress.
if (duration == -1)
{
// show elapsed time
_discordPresence.Timestamps.StartUnixMilliseconds = (ulong)(Math.Round(t.TotalSeconds) - Math.Round(_mbApiInterface.Player_GetPosition() / 1000.0));
_discordPresence.Timestamps.EndUnixMilliseconds = null;
}
}

switch (playerGetPlayState)
{
case PlayState.Playing:
SetImage(AssetManager.ASSET_PLAY, _settings.ShowOnlyNonPlayingState);
break;
case PlayState.Stopped:
SetImage(AssetManager.ASSET_STOP);
_discordPresence.Timestamps.Start = null;
_discordPresence.Timestamps.End = null;
break;
case PlayState.Paused:
SetImage(AssetManager.ASSET_PAUSE);
_discordPresence.Timestamps.Start = null;
_discordPresence.Timestamps.End = null;
break;
case PlayState.Undefined:
case PlayState.Loading:
Expand All @@ -376,32 +391,20 @@ void SetImage(string name, bool forceHideSmallImage = false)

_discordPresence.Details = padString(_layoutHandler.Render(_settings.PresenceDetails, metaDataDict, _settings.Separator));

var trackcnt = -1;
var trackno = -1;
try
{
trackcnt = int.Parse(_layoutHandler.Render(_settings.PresenceTrackCnt, metaDataDict, _settings.Separator));
trackno = int.Parse(_layoutHandler.Render(_settings.PresenceTrackNo, metaDataDict, _settings.Separator));
}
#pragma warning disable RCS1075 // Avoid empty catch clause that catches System.Exception.
catch (Exception)
#pragma warning restore RCS1075 // Avoid empty catch clause that catches System.Exception.
{
// ignored
}
var trackcnt = _layoutHandler.Render(_settings.PresenceTrackCnt, metaDataDict, _settings.Separator);
var trackno = _layoutHandler.Render(_settings.PresenceTrackNo, metaDataDict, _settings.Separator);

if (trackcnt < trackno || trackcnt <= 0 || trackno <= 0)
if (int.TryParse(trackcnt, out var trackCount) && int.TryParse(trackno, out var trackNumber))
{
_discordPresence.Party = null;
}
else
{
_discordPresence.Party = new Party
if (trackCount > trackNumber && trackCount > 0 && trackNumber > 0)
{
ID = "aaaa",
Max = trackcnt,
Size = trackno
};
_discordPresence.Party = new Party
{
ID = "aaaa",
Max = trackCount,
Size = trackNumber
};
}
}

if (!_settings.UpdatePresenceWhenStopped && (playerGetPlayState == PlayState.Paused || playerGetPlayState == PlayState.Stopped))
Expand Down
Loading