first commit
This commit is contained in:
285
SpotifyHonorific/Updaters/Updater.cs
Normal file
285
SpotifyHonorific/Updaters/Updater.cs
Normal file
@@ -0,0 +1,285 @@
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Ipc;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using Scriban;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
|
||||
namespace SpotifyHonorific.Updaters;
|
||||
|
||||
public class Updater : IDisposable
|
||||
{
|
||||
private Config Config { get; init; }
|
||||
private IFramework Framework { get; init; }
|
||||
private IDalamudPluginInterface PluginInterface { get; init; }
|
||||
private IPluginLog PluginLog { get; init; }
|
||||
private ICallGateSubscriber<int, string, object> SetCharacterTitleSubscriber { get; init; }
|
||||
private ICallGateSubscriber<int, object> ClearCharacterTitleSubscriber { get; init; }
|
||||
|
||||
private Action? UpdateTitle { get; set; }
|
||||
private string? UpdatedTitleJson { get; set; }
|
||||
private UpdaterContext UpdaterContext { get; init; } = new();
|
||||
|
||||
private Timer MediaCheckTimer { get; init; }
|
||||
private MediaActivity? CurrentMediaActivity { get; set; }
|
||||
|
||||
public Updater(Config config, IFramework framwork, IDalamudPluginInterface pluginInterface, IPluginLog pluginLog)
|
||||
{
|
||||
Config = config;
|
||||
Framework = framwork;
|
||||
PluginInterface = pluginInterface;
|
||||
PluginLog = pluginLog;
|
||||
|
||||
SetCharacterTitleSubscriber = PluginInterface.GetIpcSubscriber<int, string, object>("Honorific.SetCharacterTitle");
|
||||
ClearCharacterTitleSubscriber = PluginInterface.GetIpcSubscriber<int, object>("Honorific.ClearCharacterTitle");
|
||||
|
||||
MediaCheckTimer = new Timer(2000);
|
||||
MediaCheckTimer.Elapsed += CheckMediaActivity;
|
||||
MediaCheckTimer.AutoReset = true;
|
||||
|
||||
if (Config.Enabled)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
Framework.Update += OnFrameworkUpdate;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Framework.Update -= OnFrameworkUpdate;
|
||||
MediaCheckTimer?.Stop();
|
||||
MediaCheckTimer?.Dispose();
|
||||
Framework.RunOnFrameworkThread(() =>
|
||||
{
|
||||
ClearCharacterTitleSubscriber.InvokeAction(0);
|
||||
});
|
||||
}
|
||||
|
||||
public Task Enable(bool value)
|
||||
{
|
||||
return value ? Start() : Stop();
|
||||
}
|
||||
|
||||
public Task Restart()
|
||||
{
|
||||
return Stop().ContinueWith(t => Start());
|
||||
}
|
||||
|
||||
public Task Start()
|
||||
{
|
||||
if (Config.Enabled)
|
||||
{
|
||||
MediaCheckTimer.Start();
|
||||
PluginLog.Info("Media activity monitoring started");
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Stop()
|
||||
{
|
||||
MediaCheckTimer.Stop();
|
||||
Framework.RunOnFrameworkThread(() =>
|
||||
{
|
||||
ClearCharacterTitleSubscriber.InvokeAction(0);
|
||||
});
|
||||
PluginLog.Info("Media activity monitoring stopped");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string State()
|
||||
{
|
||||
return MediaCheckTimer.Enabled ? "Running" : "Stopped";
|
||||
}
|
||||
|
||||
private void CheckMediaActivity(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mediaActivity = GetCurrentMediaActivity();
|
||||
|
||||
if (!MediaActivitiesEqual(CurrentMediaActivity, mediaActivity))
|
||||
{
|
||||
CurrentMediaActivity = mediaActivity;
|
||||
MediaActivityUpdated(mediaActivity);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error($"Error checking media activity: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private MediaActivity? GetCurrentMediaActivity()
|
||||
{
|
||||
var spotifyTrack = GetSpotifyTrack();
|
||||
if (!string.IsNullOrEmpty(spotifyTrack))
|
||||
{
|
||||
string artist = "";
|
||||
string songName = spotifyTrack;
|
||||
var parts = spotifyTrack.Split(new[] { " - " }, 2, StringSplitOptions.None);
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
artist = parts[0];
|
||||
songName = parts[1];
|
||||
}
|
||||
|
||||
return new MediaActivity
|
||||
{
|
||||
Name = "Spotify (V1)",
|
||||
SongName = songName,
|
||||
Artist = artist,
|
||||
Type = ActivityType.Listening
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? GetSpotifyTrack()
|
||||
{
|
||||
try
|
||||
{
|
||||
var spotifyProcesses = Process.GetProcessesByName("Spotify");
|
||||
foreach (var process in spotifyProcesses)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(process.MainWindowTitle) &&
|
||||
process.MainWindowTitle != "Spotify" &&
|
||||
process.MainWindowTitle != "Spotify Premium" &&
|
||||
process.MainWindowTitle != "Spotify Free")
|
||||
{
|
||||
return process.MainWindowTitle;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Debug($"Error getting Spotify track: {ex.Message}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool MediaActivitiesEqual(MediaActivity? a, MediaActivity? b)
|
||||
{
|
||||
if (a == null && b == null) return true;
|
||||
if (a == null || b == null) return false;
|
||||
return a.Name == b.Name && a.SongName == b.SongName && a.Type == b.Type;
|
||||
}
|
||||
|
||||
private void MediaActivityUpdated(MediaActivity? mediaActivity)
|
||||
{
|
||||
PluginLog.Verbose($"MediaActivityUpdated: {JsonConvert.SerializeObject(mediaActivity, Formatting.Indented)}");
|
||||
|
||||
if (mediaActivity != null)
|
||||
{
|
||||
foreach (var activityConfig in Config.ActivityConfigs.Where(c => c.Enabled).OrderByDescending(c => c.Priority))
|
||||
{
|
||||
var matchesType =
|
||||
(mediaActivity.Type == ActivityType.Listening);
|
||||
PluginLog.Verbose($"Checking activity config '{activityConfig.Name}' for match: {matchesType}");
|
||||
if (matchesType)
|
||||
{
|
||||
var matchFilter = true;
|
||||
if (!activityConfig.FilterTemplate.IsNullOrWhitespace())
|
||||
{
|
||||
var filterTemplate = Template.Parse(activityConfig.FilterTemplate);
|
||||
var filter = filterTemplate.Render(new { Activity = mediaActivity, Context = UpdaterContext }, member => member.Name);
|
||||
|
||||
if (bool.TryParse(filter, out var parsedFilter))
|
||||
{
|
||||
matchFilter = parsedFilter;
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginLog.Error($"Unable to parse filter '{filter}' as boolean, skipping result");
|
||||
}
|
||||
}
|
||||
|
||||
if (matchFilter)
|
||||
{
|
||||
UpdaterContext.SecsElapsed = 0;
|
||||
UpdateTitle = () =>
|
||||
{
|
||||
if (Config.Enabled && activityConfig.Enabled)
|
||||
{
|
||||
var titleTemplate = Template.Parse(activityConfig.TitleTemplate);
|
||||
var title = titleTemplate.Render(new { Activity = mediaActivity, Context = UpdaterContext }, member => member.Name);
|
||||
|
||||
var data = new Dictionary<string, object>() {
|
||||
{"Title", title},
|
||||
{"IsPrefix", activityConfig.IsPrefix},
|
||||
{"Color", activityConfig.Color!},
|
||||
{"Glow", activityConfig.Glow!}
|
||||
};
|
||||
|
||||
var serializedData = JsonConvert.SerializeObject(data, Formatting.Indented);
|
||||
if (serializedData != UpdatedTitleJson)
|
||||
{
|
||||
PluginLog.Verbose($"Call Honorific SetCharacterTitle IPC with:\n{serializedData}");
|
||||
SetCharacterTitleSubscriber.InvokeAction(0, serializedData);
|
||||
UpdatedTitleJson = serializedData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearTitle();
|
||||
}
|
||||
};
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (UpdateTitle != null || UpdatedTitleJson != null)
|
||||
{
|
||||
ClearTitle();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFrameworkUpdate(IFramework framework)
|
||||
{
|
||||
if (Config.Enabled && UpdateTitle != null)
|
||||
{
|
||||
UpdateTitle.Invoke();
|
||||
UpdaterContext.SecsElapsed += framework.UpdateDelta.TotalSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearTitle()
|
||||
{
|
||||
PluginLog.Verbose("Call Honorific ClearCharacterTitle IPC");
|
||||
Framework.RunOnFrameworkThread(() =>
|
||||
{
|
||||
ClearCharacterTitleSubscriber.InvokeAction(0);
|
||||
});
|
||||
UpdaterContext.SecsElapsed = 0;
|
||||
UpdateTitle = null;
|
||||
UpdatedTitleJson = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class MediaActivity
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string SongName { get; set; } = "";
|
||||
public string Artist { get; set; } = "";
|
||||
public ActivityType Type { get; set; }
|
||||
}
|
||||
|
||||
public enum ActivityType
|
||||
{
|
||||
Playing,
|
||||
Streaming,
|
||||
Listening,
|
||||
Watching,
|
||||
Custom,
|
||||
Competing
|
||||
}
|
||||
6
SpotifyHonorific/Updaters/UpdaterContext.cs
Normal file
6
SpotifyHonorific/Updaters/UpdaterContext.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace SpotifyHonorific.Updaters;
|
||||
|
||||
public class UpdaterContext
|
||||
{
|
||||
public double SecsElapsed { get; set; } = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user