mirror of
https://github.com/IAmParadox27/jellyfin-plugin-media-bar.git
synced 2026-11-13 16:54:19 +01:00
Added support for avatars/list.txt to be served from a playlist. Added an option to use the physical file or the playlist, and a text box to name the playlist.
This commit is contained in:
1 parent
767be18e47
commit
66ed5358ee
6 files changed
+137
-4
No files matched your search
@@ -11,5 +11,9 @@ namespace Jellyfin.Plugin.MediaBar.Configuration
|
||||
public class PluginConfiguration : BasePluginConfiguration
|
||||
{
|
||||
public MediaBarState Enabled { get; set; } = MediaBarState.Enabled;
|
||||
|
||||
public bool UseAvatarsFile { get; set; } = true;
|
||||
|
||||
public string AvatarsPlaylist { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,24 @@
|
||||
</select>
|
||||
<span>Whether the media bar should appear or not.</span>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label class="emby-checkbox-label">
|
||||
<input type="checkbox" id="chkUseAvatarsFile" is="emby-checkbox" class="emby-checkbox" data-id="chkUseAvatarsFile" />
|
||||
<span class="checkboxLabel">Use physical avatars file</span>
|
||||
<span class="checkboxOutline">
|
||||
<span class="material-icons checkboxIcon checkboxIcon-checked check" aria-hidden="true"></span>
|
||||
<span class="material-icons checkboxIcon checkboxIcon-unchecked " aria-hidden="true"></span>
|
||||
</span>
|
||||
</label>
|
||||
<div class="fieldDescription">If checked, the plugin will look for a list.txt file in the avatars directory at the root of jellyfin-web.</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="txtAvatarsPlaylist">Avatars Playlist</label>
|
||||
<label class="inputLabel inputLabel-float inputLabelUnfocused" for="txtAvatarsPlaylist"></label>
|
||||
<input id="txtAvatarsPlaylist" type="text" is="emby-input" class="emby-input" data-id="txtAvatarsPlaylist" />
|
||||
<div class="fieldDescription">If populated, and "Use physical avatars file" is disabled, this is the name of the playlist which is used to populate the media bar.<br />
|
||||
If empty, the media bar will randomly populate.</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button id="saveConfig" is="emby-button" type="submit" class="raised button-submit block">
|
||||
@@ -49,6 +67,8 @@
|
||||
Dashboard.showLoadingMsg();
|
||||
const config = {
|
||||
Enabled: document.querySelector("[data-id=enabledSelect]").value,
|
||||
UseAvatarsFile: document.querySelector("[data-id=chkUseAvatarsFile]").checked,
|
||||
AvatarsPlaylist: document.querySelector("[data-id=txtAvatarsPlaylist]").value,
|
||||
};
|
||||
|
||||
window.ApiClient.updatePluginConfiguration(MediaBarConfig.pluginId, config)
|
||||
@@ -65,6 +85,8 @@
|
||||
window.ApiClient.getPluginConfiguration(MediaBarConfig.pluginId)
|
||||
.then(function (config) {
|
||||
document.querySelector("[data-id=enabledSelect]").value = config.Enabled;
|
||||
document.querySelector("[data-id=chkUseAvatarsFile]").checked = config.UseAvatarsFile;
|
||||
document.querySelector("[data-id=txtAvatarsPlaylist]").value = config.AvatarsPlaylist;
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using Jellyfin.Extensions;
|
||||
using Jellyfin.Plugin.MediaBar.Helpers;
|
||||
using Jellyfin.Plugin.MediaBar.Model;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
|
||||
namespace Jellyfin.Plugin.MediaBar.Controllers
|
||||
{
|
||||
@@ -33,6 +37,19 @@ namespace Jellyfin.Plugin.MediaBar.Controllers
|
||||
return Content(fileContents, contentType);
|
||||
}
|
||||
|
||||
[HttpPost("Avatar/List")]
|
||||
public ActionResult GetAvatarsList([FromBody] PatchRequestPayload payload, [FromServices] IPlaylistManager playlistManager, [FromServices] IUserManager userManager)
|
||||
{
|
||||
string? content = TransformationPatches.AvatarsList(payload, playlistManager, userManager);
|
||||
|
||||
if (content == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return Content(content, "text/plain");
|
||||
}
|
||||
|
||||
[HttpPost("Patch/IndexHtml")]
|
||||
public ActionResult PatchIndexHtml([FromBody] PatchRequestPayload payload)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,78 @@
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using Jellyfin.Extensions;
|
||||
using Jellyfin.Plugin.MediaBar.Model;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
|
||||
namespace Jellyfin.Plugin.MediaBar.Helpers
|
||||
{
|
||||
public static class TransformationPatches
|
||||
{
|
||||
public static string? AvatarsList(PatchRequestPayload payload, IPlaylistManager playlistManager, IUserManager userManager)
|
||||
{
|
||||
if (MediaBarPlugin.Instance.Configuration.UseAvatarsFile)
|
||||
{
|
||||
return payload.Contents;
|
||||
}
|
||||
|
||||
IEnumerable<Guid> allUserIds = userManager.UsersIds;
|
||||
|
||||
Playlist? playlist = null;
|
||||
Guid? userIdToUse = null;
|
||||
|
||||
foreach (Guid userId in allUserIds)
|
||||
{
|
||||
playlist = playlistManager.GetPlaylists(userId)
|
||||
.FirstOrDefault(x => x.Name == MediaBarPlugin.Instance.Configuration.AvatarsPlaylist);
|
||||
|
||||
if (playlist != null)
|
||||
{
|
||||
userIdToUse = userId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (playlist == null || userIdToUse == null)
|
||||
{
|
||||
return payload.Contents;
|
||||
}
|
||||
|
||||
IEnumerable<Tuple<LinkedChild, BaseItem>> itemsRaw = playlist.GetManageableItems()
|
||||
.Where(i => i.Item2.IsVisible(userManager.GetUserById(userIdToUse.Value)));
|
||||
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
|
||||
stringWriter.WriteLine(MediaBarPlugin.Instance.Configuration.AvatarsPlaylist);
|
||||
|
||||
List<Guid> idsWritten = new List<Guid>();
|
||||
|
||||
foreach (Tuple<LinkedChild, BaseItem> item in itemsRaw)
|
||||
{
|
||||
BaseItem itemToUse = item.Item2;
|
||||
if (item.Item2 is Episode episode)
|
||||
{
|
||||
itemToUse = episode.Series;
|
||||
}
|
||||
|
||||
if (!idsWritten.Contains(itemToUse.Id))
|
||||
{
|
||||
idsWritten.Add(itemToUse.Id);
|
||||
}
|
||||
}
|
||||
|
||||
idsWritten.Shuffle();
|
||||
|
||||
foreach (Guid id in idsWritten)
|
||||
{
|
||||
stringWriter.WriteLine(id);
|
||||
}
|
||||
|
||||
return stringWriter.ToString();
|
||||
}
|
||||
|
||||
public static string IndexHtml(PatchRequestPayload payload)
|
||||
{
|
||||
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(MediaBarPlugin).Namespace}.Inject.index.html")!;
|
||||
|
||||
@@ -11,9 +11,12 @@ namespace Jellyfin.Plugin.MediaBar
|
||||
public override Guid Id => Guid.Parse("08f615ea-2107-4f04-89cc-091035f54448");
|
||||
|
||||
public override string Name => "Media Bar";
|
||||
|
||||
|
||||
public static MediaBarPlugin Instance { get; private set; } = null!;
|
||||
|
||||
public MediaBarPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer, IServiceProvider serviceProvider) : base(applicationPaths, xmlSerializer)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public IEnumerable<PluginPageInfo> GetPages()
|
||||
|
||||
@@ -7,6 +7,8 @@ using Jellyfin.Plugin.MediaBar.Helpers;
|
||||
using Jellyfin.Plugin.MediaBar.Model;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
@@ -27,12 +29,17 @@ namespace Jellyfin.Plugin.MediaBar.Services
|
||||
private readonly IServerApplicationHost m_serverApplicationHost;
|
||||
private readonly ILogger<MediaBarPlugin> m_logger;
|
||||
private readonly NamedPipeService m_namedPipeService;
|
||||
private readonly IUserManager m_userManager;
|
||||
private readonly IPlaylistManager m_playlistManager;
|
||||
|
||||
public StartupService(IServerApplicationHost serverApplicationHost, ILogger<MediaBarPlugin> logger, NamedPipeService namedPipeService)
|
||||
public StartupService(IServerApplicationHost serverApplicationHost, ILogger<MediaBarPlugin> logger, NamedPipeService namedPipeService,
|
||||
IUserManager userManager, IPlaylistManager playlistManager)
|
||||
{
|
||||
m_serverApplicationHost = serverApplicationHost;
|
||||
m_logger = logger;
|
||||
m_namedPipeService = namedPipeService;
|
||||
m_userManager = userManager;
|
||||
m_playlistManager = playlistManager;
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
@@ -71,6 +78,19 @@ namespace Jellyfin.Plugin.MediaBar.Services
|
||||
|
||||
payloads.Add(payload);
|
||||
}
|
||||
{
|
||||
JObject payload = new JObject();
|
||||
payload.Add("id", "8d374d6b-3c5b-464a-a2a2-96e92fa81345");
|
||||
payload.Add("fileNamePattern", "avatars/list.txt");
|
||||
payload.Add("transformationEndpoint", "/MediaBar/Avatar/List");
|
||||
payload.Add("transformationPipe", "Jellyfin.Plugin.MediaBar.AvatarsList");
|
||||
RegisterPipeEndpoint("Jellyfin.Plugin.MediaBar.AvatarsList", innerPayload =>
|
||||
{
|
||||
return TransformationPatches.AvatarsList(innerPayload, m_playlistManager, m_userManager) ?? "";
|
||||
});
|
||||
|
||||
payloads.Add(payload);
|
||||
}
|
||||
|
||||
string fileTransformationPipeName = "Jellyfin.Plugin.FileTransformation.NamedPipe";
|
||||
MethodInfo? getPipePathMethod = typeof(PipeStream).GetMethod("GetPipePath", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
@@ -87,7 +107,7 @@ namespace Jellyfin.Plugin.MediaBar.Services
|
||||
|
||||
await pipeClient.WriteAsync(BitConverter.GetBytes((long)payloadBytes.Length));
|
||||
await pipeClient.WriteAsync(payloadBytes, 0, payloadBytes.Length);
|
||||
|
||||
|
||||
pipeClient.ReadByte();
|
||||
|
||||
await pipeClient.DisposeAsync();
|
||||
|
||||
Reference in new issue
Block a user