feat: enable collections.
This commit is contained in:
parent
6ac75835f0
commit
aa6fed146d
8 changed files with 172 additions and 12 deletions
|
@ -54,7 +54,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Api {
|
|||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public async Task<ActionResult> SetCollection([FromRoute, Required] CollectionId collectionId, [FromBody] SmartCollectionDto smartCollection) {
|
||||
public async Task<ActionResult> SetCollection([FromBody, Required] SmartCollectionDto smartCollection) {
|
||||
await _store.SaveSmartCollectionAsync(smartCollection);
|
||||
return Created();
|
||||
}
|
||||
|
|
|
@ -279,7 +279,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
|||
IList<Expression> r = new List<Expression>();
|
||||
MethodInfo? mi = o.Value().GetType().GetMethod(s.Value(), l_types);
|
||||
if (mi == null) {
|
||||
throw new ApplicationException($"{o.Value()} has no method {s.Value()}");
|
||||
throw new ApplicationException($"{o.Value()} ({o.Value().GetType()}) has no method {s.Value()}");
|
||||
}
|
||||
|
||||
return Object.FromBase(mi.Invoke(o.Value(), l_));
|
||||
|
|
51
Jellyfin.Plugin.SmartPlaylist/Pages/smartCollections.html
Normal file
51
Jellyfin.Plugin.SmartPlaylist/Pages/smartCollections.html
Normal file
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SmartCollection</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="SmartCollectionConfigPage" data-role="page" class="page type-interior pluginConfigurationPage" data-require="emby-input,emby-button,emby-select,emby-checkbox" data-controller="__plugin/smartCollections.js">
|
||||
<div data-role="content">
|
||||
<div class="content-primary">
|
||||
<form id="SmartCollectionConfigForm">
|
||||
<div>
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartcollectionSelection">Choose a collection to edit</label>
|
||||
<select id="SmartcollectionSelection" class="emby-select">
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartcollectionEditName">Name</label>
|
||||
<input id="SmartcollectionEditName" type="text" class="emby-input"/>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartcollectionEditProgram">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="SmartcollectionEditProgram" class="emby-input smartcollection-monospace" name="Program" rows="16" cols="120"></textarea>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartcollectionEditSortProgram">Sort Program</label>
|
||||
<div class="fieldDescription">A program which should return a list of items to include in the collection, sorted however you like.</div>
|
||||
<textarea id="SmartcollectionEditSortProgram" class="emby-input smartcollection-monospace" name="SortProgram" rows="16" cols="120"></textarea>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartcollectionEditEnabled">Enabled</label>
|
||||
<div class="fieldDescription">Is the collection enabled.</div>
|
||||
<input id="SmartcollectionEditEnabled" type="checkbox" class="emby-input"/>
|
||||
</div>
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block emby-button">
|
||||
<span>Save</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.smartcollection-monospace {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
111
Jellyfin.Plugin.SmartPlaylist/Pages/smartCollections.js
Normal file
111
Jellyfin.Plugin.SmartPlaylist/Pages/smartCollections.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
|
||||
var COLLECTIONS = [
|
||||
{
|
||||
Id: 'My New Smartcollection',
|
||||
Name: 'My New Smartcollection',
|
||||
Program: '(is-favourite)',
|
||||
SortProgram: '(begin *items*)',
|
||||
CollectionId: '00000000000000000000000000000000',
|
||||
Enabled: true,
|
||||
}
|
||||
];
|
||||
|
||||
function fillForm(collection) {
|
||||
const editName = document.querySelector('#SmartcollectionEditName');
|
||||
const editProgram = document.querySelector('#SmartcollectionEditProgram');
|
||||
const editSortProgram = document.querySelector('#SmartcollectionEditSortProgram');
|
||||
const editEnabled = document.querySelector('#SmartcollectionEditEnabled');
|
||||
editName.value = collection.Name;
|
||||
editProgram.value = collection.Program;
|
||||
editSortProgram.value = collection.SortProgram;
|
||||
editEnabled.checked = collection.Enabled;
|
||||
}
|
||||
|
||||
function fillCollectionSelect(collections) {
|
||||
const selection = document.querySelector('#SmartcollectionSelection');
|
||||
selection.innerHTML = '';
|
||||
var o = document.createElement('option');
|
||||
o.value = null;
|
||||
o.innerHTML = 'Create new collection ...';
|
||||
selection.appendChild(o);
|
||||
for (const i of collections.slice(1)) {
|
||||
var o = document.createElement('option');
|
||||
o.value = i.Id;
|
||||
o.innerHTML = i.Name;
|
||||
selection.appendChild(o);
|
||||
}
|
||||
}
|
||||
|
||||
function jsonFromForm(collectionId) {
|
||||
const editName = document.querySelector('#SmartcollectionEditName');
|
||||
const editProgram = document.querySelector('#SmartcollectionEditProgram');
|
||||
const editSortProgram = document.querySelector('#SmartcollectionEditSortProgram');
|
||||
const editEnabled = document.querySelector('#SmartcollectionEditEnabled');
|
||||
if (collectionId === null) {
|
||||
collectionId = '00000000000000000000000000000000'
|
||||
}
|
||||
return {
|
||||
Id: editName.value,
|
||||
Name: editName.value,
|
||||
Program: editProgram.value,
|
||||
SortProgram: editSortProgram.value,
|
||||
CollectionId: collectionId,
|
||||
Enabled: editEnabled.checked,
|
||||
};
|
||||
}
|
||||
|
||||
ApiClient.getSmartCollections = function () {
|
||||
const url = ApiClient.getUrl('SmartCollection');
|
||||
return this.ajax({
|
||||
type: 'GET',
|
||||
url: url,
|
||||
dataType: 'json',
|
||||
});
|
||||
}
|
||||
|
||||
ApiClient.setSmartCollection = function (c) {
|
||||
const url = ApiClient.getUrl('SmartCollection');
|
||||
return this.ajax({
|
||||
type: 'POST',
|
||||
url: url,
|
||||
dataType: 'json',
|
||||
contentType: 'application/json; charset=UTF-8',
|
||||
data: JSON.stringify(c),
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelector('#SmartCollectionConfigPage')
|
||||
.addEventListener('viewshow', function() {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getSmartCollections().then(function (collections) {
|
||||
COLLECTIONS = [COLLECTIONS[0]].concat(collections);
|
||||
const selection = document.querySelector('#SmartcollectionSelection');
|
||||
fillCollectionSelect(COLLECTIONS);
|
||||
fillForm(COLLECTIONS[selection.selectedIndex]);
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector('#SmartcollectionSelection')
|
||||
.addEventListener('change', function() {
|
||||
const selection = document.querySelector('#SmartcollectionSelection');
|
||||
fillForm(COLLECTIONS[selection.selectedIndex]);
|
||||
});
|
||||
|
||||
document.querySelector('#SmartCollectionConfigForm')
|
||||
.addEventListener('submit', function (e) {
|
||||
Dashboard.showLoadingMsg();
|
||||
const selection = document.querySelector('#SmartcollectionSelection');
|
||||
const selectedid = COLLECTIONS[selection.selectedIndex].Id;
|
||||
ApiClient.setSmartCollection(jsonFromForm(COLLECTIONS[selection.selectedIndex].CollectionId)).then(function () {
|
||||
ApiClient.getSmartCollections().then(function (collections) {
|
||||
COLLECTIONS = [COLLECTIONS[0]].concat(collections);
|
||||
fillCollectionSelect(COLLECTIONS);
|
||||
const idx = COLLECTIONS.map(x => x.Id).indexOf(selectedid);
|
||||
selection.selectedIndex = idx;
|
||||
fillForm(COLLECTIONS[selection.selectedIndex]);
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
e.preventDefault();
|
||||
});
|
|
@ -35,7 +35,7 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="SmartPlaylistEditEnabled">Enabled</label>
|
||||
<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>
|
||||
|
|
|
@ -98,7 +98,7 @@ ApiClient.setSmartPlaylist = function (p) {
|
|||
}
|
||||
|
||||
document.querySelector('#SmartPlaylistConfigPage')
|
||||
.addEventListener('pageshow', function() {
|
||||
.addEventListener('viewshow', function() {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getSmartPlaylists().then(function (playlists) {
|
||||
PLAYLISTS = [PLAYLISTS[0]].concat(playlists);
|
||||
|
@ -106,8 +106,6 @@ document.querySelector('#SmartPlaylistConfigPage')
|
|||
USERS = users;
|
||||
const selection = document.querySelector('#SmartplaylistSelection');
|
||||
fillPlaylistSelect(PLAYLISTS);
|
||||
console.log('selectedIndex =', selection.selectedIndex);
|
||||
console.log('selectedIndex =', PLAYLISTS[selection.selectedIndex]);
|
||||
fillForm(PLAYLISTS[selection.selectedIndex], USERS);
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
|
@ -117,7 +115,6 @@ document.querySelector('#SmartPlaylistConfigPage')
|
|||
document.querySelector('#SmartplaylistSelection')
|
||||
.addEventListener('change', function() {
|
||||
const selection = document.querySelector('#SmartplaylistSelection');
|
||||
console.log('p =', PLAYLISTS[selection.selectedIndex]);
|
||||
fillForm(PLAYLISTS[selection.selectedIndex], USERS);
|
||||
});
|
||||
|
||||
|
@ -140,5 +137,4 @@ document.querySelector('#SmartPlaylistConfigForm')
|
|||
});
|
||||
});
|
||||
e.preventDefault();
|
||||
})
|
||||
|
||||
});
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
},
|
||||
new PluginPageInfo {
|
||||
Name = "Smart Playlists",
|
||||
DisplayName = "Smart Playlists",
|
||||
EmbeddedResourcePath = string.Format(CultureInfo.InvariantCulture, "{0}.Pages.smartPlaylists.html", GetType().Namespace),
|
||||
EnableInMainMenu = true,
|
||||
},
|
||||
|
@ -44,8 +45,9 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
},
|
||||
new PluginPageInfo {
|
||||
Name = "Smart Collections",
|
||||
DisplayName = "Smart Collections",
|
||||
EmbeddedResourcePath = string.Format(CultureInfo.InvariantCulture, "{0}.Pages.smartCollections.html", GetType().Namespace),
|
||||
//EnableInMainMenu = true,
|
||||
EnableInMainMenu = true,
|
||||
},
|
||||
new PluginPageInfo {
|
||||
Name = "smartCollections.js",
|
||||
|
|
|
@ -101,8 +101,8 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
|||
if (_libraryManager.GetItemById(collectionId) is not BoxSet collection) {
|
||||
throw new ArgumentException("");
|
||||
}
|
||||
var existingItems = collection.Children;
|
||||
await _collectionManager.RemoveFromCollectionAsync(collectionId, existingItems.Select(x => x.Id));
|
||||
var existingItems = collection.LinkedChildren.Select(x => x.ItemId).Where(x => x != null).Select(x => x.Value);
|
||||
await _collectionManager.RemoveFromCollectionAsync(collectionId, existingItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue