Compare commits
2 commits
4d2d22e486
...
097d267d24
Author | SHA1 | Date | |
---|---|---|---|
097d267d24 | |||
28f3cc682e |
5 changed files with 178 additions and 2 deletions
|
@ -3,14 +3,22 @@ using MediaBrowser.Common.Configuration;
|
|||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Model.Plugins;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
||||
namespace Jellyfin.Plugin.SmartPlaylist {
|
||||
public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages {
|
||||
public IServerApplicationPaths ServerApplicationPaths;
|
||||
public IUserManager UserManager;
|
||||
public Plugin(
|
||||
IApplicationPaths applicationPaths,
|
||||
IXmlSerializer xmlSerializer
|
||||
IXmlSerializer xmlSerializer,
|
||||
IServerApplicationPaths serverApplicationPaths,
|
||||
IUserManager userManager
|
||||
) : base (applicationPaths, xmlSerializer) {
|
||||
Instance = this;
|
||||
ServerApplicationPaths = serverApplicationPaths;
|
||||
UserManager = userManager;
|
||||
}
|
||||
public static Plugin? Instance {get; private set; }
|
||||
public override string Name => "Smart Playlist";
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Model.Plugins;
|
||||
using MediaBrowser.Controller;
|
||||
|
||||
namespace Jellyfin.Plugin.SmartPlaylist {
|
||||
public class PluginConfiguration : BasePluginConfiguration {
|
||||
|
@ -42,7 +43,30 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
(define find-parent (lambda (typename) (invoke-generic item "FindParent" nil (list typename))))
|
||||
(define find-artist (lambda nil (find-parent "MediaBrowser.Controller.Entities.Audio.MusicArtist, MediaBrowser.Controller"))))
|
||||
""";
|
||||
store = new Store(new SmartPlaylistFileSystem(Plugin.Instance.ServerApplicationPaths));
|
||||
}
|
||||
private Store store { get; set; }
|
||||
public string InitialProgram { get; set; }
|
||||
public SmartPlaylistDto[] Playlists {
|
||||
get {
|
||||
return store.GetAllSmartPlaylistsAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
set {
|
||||
var existing = store.GetAllSmartPlaylistsAsync().GetAwaiter().GetResult().Select(x => x.Id).ToList();
|
||||
foreach (var p in value) {
|
||||
existing.Remove(p.Id);
|
||||
store.SaveSmartPlaylistAsync(p).GetAwaiter().GetResult();
|
||||
}
|
||||
foreach (var p in existing) {
|
||||
store.DeleteSmartPlaylistById(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
public object[][] Users {
|
||||
get {
|
||||
return Plugin.Instance.UserManager.Users.Select(x => new object[]{x.Id, x.Username}).ToArray();
|
||||
}
|
||||
set { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,6 +166,9 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
|||
_logger.LogDebug("- {0}", asm);
|
||||
}
|
||||
foreach (SmartPlaylistDto dto in await _store.GetAllSmartPlaylistsAsync()) {
|
||||
if (!dto.Enabled) {
|
||||
continue;
|
||||
}
|
||||
var changedDto = false;
|
||||
if (dto.Playlists.Length == 0) {
|
||||
dto.Playlists = _userManager.UsersIds.Select(x => new SmartPlaylistLinkDto {
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
Task<SmartPlaylistDto> GetSmartPlaylistAsync(SmartPlaylistId smartPlaylistId);
|
||||
Task<SmartPlaylistDto[]> GetAllSmartPlaylistsAsync();
|
||||
Task SaveSmartPlaylistAsync(SmartPlaylistDto smartPlaylist);
|
||||
void DeleteSmartPlaylistById(SmartPlaylistId smartPlaylistId);
|
||||
void DeleteSmartPlaylist(SmartPlaylistDto smartPlaylist);
|
||||
}
|
||||
|
||||
|
@ -48,7 +49,7 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
var text = new SerializerBuilder().Build().Serialize(smartPlaylist);
|
||||
await File.WriteAllTextAsync(filename, text);
|
||||
}
|
||||
private void DeleteSmartPlaylistById(SmartPlaylistId smartPlaylistId) {
|
||||
public void DeleteSmartPlaylistById(SmartPlaylistId smartPlaylistId) {
|
||||
try {
|
||||
string filename = _fileSystem.FindSmartPlaylistFilePath(smartPlaylistId);
|
||||
if (File.Exists(filename)) { File.Delete(filename); }
|
||||
|
|
|
@ -14,6 +14,36 @@
|
|||
<div class="fieldDescription">A program which can set up the environment</div>
|
||||
<textarea id="InitialProgram" class="emby-input smartplaylist-monospace" name="InitialProgram" rows="16" cols="120"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartplaylistSelection">Choose a playlist to edit</label>
|
||||
<select id="SmartplaylistSelection" class="emby-select">
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartplaylistEditName">Name</label>
|
||||
<input id="SmartplaylistEditName" type="text" class="emby-input"/>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartplaylistEditProgram">Program</label>
|
||||
<div class="fieldDescription">A program which should return <code>t</code> or <code>nil</code> to include or exclude the provided <code>item</code>.</div>
|
||||
<textarea id="SmartplaylistEditProgram" class="emby-input smartplaylist-monospace" name="Program" rows="16" cols="120"></textarea>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartplaylistEditSortProgram">Sort Program</label>
|
||||
<div class="fieldDescription">A program which should return a list of items to include in the playlist, sorted however you like.</div>
|
||||
<textarea id="SmartplaylistEditSortProgram" class="emby-input smartplaylist-monospace" name="SortProgram" rows="16" cols="120"></textarea>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartplaylistEditUsers">Users</label>
|
||||
<div class="fieldDescription">Which users should get access to the playlist.</div>
|
||||
<select multiple id="SmartplaylistEditUsers" class="emby-select">
|
||||
</select>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartPlaylistEditEnabled">Enabled</label>
|
||||
<div class="fieldDescription">Is the playlist enabled.</div>
|
||||
<input id="SmartplaylistEditEnabled" type="checkbox" class="emby-input"/>
|
||||
</div>
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block emby-button">
|
||||
<span>Save</span>
|
||||
|
@ -32,11 +62,82 @@
|
|||
pluginUniqueId: 'dd2326e3-4d3e-4bfc-80e6-28502c1131df'
|
||||
};
|
||||
|
||||
function changeEditBox(config, id) {
|
||||
const selection = document.querySelector('#SmartplaylistSelection');
|
||||
const editName = document.querySelector('#SmartplaylistEditName');
|
||||
const editProgram = document.querySelector('#SmartplaylistEditProgram');
|
||||
const editSortProgram = document.querySelector('#SmartplaylistEditSortProgram');
|
||||
const editUsers = document.querySelector('#SmartplaylistEditUsers');
|
||||
const editEnabled = document.querySelector('#SmartplaylistEditEnabled');
|
||||
if (id === null) {
|
||||
selection.selectedIndex = 0;
|
||||
editName.value = '';
|
||||
editProgram.value = '';
|
||||
editSortProgram.value = '';
|
||||
editUsers.innerHTML = '';
|
||||
for (const u of config.Users) {
|
||||
var o = document.createElement('option');
|
||||
o.value = u[0];
|
||||
o.innerHTML = u[1];
|
||||
editUsers.appendChild(o);
|
||||
}
|
||||
editEnabled.checked = false;
|
||||
return;
|
||||
}
|
||||
function matchId(p) {
|
||||
return p.Id == id;
|
||||
}
|
||||
const index = config.Playlists.map(function (x) { return x.Id }).indexOf(id);
|
||||
selection.selectedIndex = index + 1;
|
||||
const p = config.Playlists[index];
|
||||
editName.value = p.Name;
|
||||
editProgram.value = p.Program;
|
||||
editSortProgram.value = p.SortProgram;
|
||||
editUsers.innerHTML = '';
|
||||
for (const u of config.Users) {
|
||||
var o = document.createElement('option');
|
||||
o.value = u[0];
|
||||
o.innerHTML = u[1];
|
||||
if (p.Playlists.map((x) => x.UserId).includes(u[0])) {
|
||||
o.setAttribute('selected', 'selected');
|
||||
}
|
||||
editUsers.appendChild(o);
|
||||
}
|
||||
editEnabled.checked = p.Enabled;
|
||||
}
|
||||
|
||||
function fillPlaylistSelect(config) {
|
||||
const selection = document.querySelector('#SmartplaylistSelection');
|
||||
selection.innerHTML = '';
|
||||
var o = document.createElement('option');
|
||||
o.value = null;
|
||||
o.innerHTML = 'Create new playlist ...';
|
||||
selection.appendChild(o);
|
||||
for (const i of config.Playlists) {
|
||||
var o = document.createElement('option');
|
||||
o.value = i.Id;
|
||||
o.innerHTML = i.Name;
|
||||
selection.appendChild(o);
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelector('#SmartPlaylistConfigPage')
|
||||
.addEventListener('pageshow', function() {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(SmartPlaylistConfig.pluginUniqueId).then(function (config) {
|
||||
document.querySelector('#InitialProgram').value = config.InitialProgram;
|
||||
fillPlaylistSelect(config);
|
||||
changeEditBox(config, (config.Playlists.length > 0) ? config.Playlists[0].Id : null);
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector('#SmartplaylistSelection')
|
||||
.addEventListener('change', function() {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(SmartPlaylistConfig.pluginUniqueId).then(function (config) {
|
||||
const selection = document.querySelector('#SmartplaylistSelection');
|
||||
changeEditBox(config, (selection.selectedIndex > 0) ? config.Playlists[selection.selectedIndex - 1].Id : null);
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
@ -46,9 +147,48 @@
|
|||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(SmartPlaylistConfig.pluginUniqueId).then(function (config) {
|
||||
config.InitialProgram = document.querySelector('#InitialProgram').value;
|
||||
const selection = document.querySelector('#SmartplaylistSelection');
|
||||
const editName = document.querySelector('#SmartplaylistEditName');
|
||||
const editProgram = document.querySelector('#SmartplaylistEditProgram');
|
||||
const editSortProgram = document.querySelector('#SmartplaylistEditSortProgram');
|
||||
const editUsers = document.querySelector('#SmartplaylistEditUsers');
|
||||
const editEnabled = document.querySelector('#SmartplaylistEditEnabled');
|
||||
var index = selection.selectedIndex;
|
||||
if (index === 0) {
|
||||
const o = {
|
||||
Id: editName.value,
|
||||
Name: editName.value,
|
||||
Program: editProgram.value,
|
||||
SortProgram: editSortProgram.value,
|
||||
Playlists: Array.from(editUsers.options).filter((x) => x.selected).map((x) => {
|
||||
const m = {UserId: x.value, PlaylistId: "00000000-0000-0000-0000-000000000000"};
|
||||
return m;
|
||||
}),
|
||||
Enabled: editEnabled.checked,
|
||||
};
|
||||
config.Playlists.push(o);
|
||||
} else {
|
||||
config.Playlists[index-1].Id = editName.value;
|
||||
config.Playlists[index-1].Name = editName.value;
|
||||
config.Playlists[index-1].Program = editProgram.value;
|
||||
config.Playlists[index-1].SortProgram = editSortProgram.value;
|
||||
config.Playlists[index-1].Playlists = Array.from(editUsers.options).filter((x) => x.selected).map((x) => {
|
||||
const existing = config.Playlists[index-1].Playlists.filter((x_) => x_.UserId === x.value).map((x_) => x_.PlaylistId);
|
||||
const m = {UserId: x.value, PlaylistId: ((existing.length > 0) ? existing[0] : "00000000-0000-0000-0000-000000000000")};
|
||||
return m;
|
||||
}),
|
||||
config.Playlists[index-1].Enabled = editEnabled.checked;
|
||||
}
|
||||
ApiClient.updatePluginConfiguration(SmartPlaylistConfig.pluginUniqueId, config).then(function (result) {
|
||||
Dashboard.processPluginConfigurationUpdateResult(result);
|
||||
ApiClient.getPluginConfiguration(SmartPlaylistConfig.pluginUniqueId).then(function (config) {
|
||||
document.querySelector('#InitialProgram').value = config.InitialProgram;
|
||||
fillPlaylistSelect(config);
|
||||
changeEditBox(config, (config.Playlists.length > 0) ? config.Playlists[0].Id : null);
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
|
|
Loading…
Reference in a new issue