UserData bound to ExternalId, Resume play seems still not working. Rename music to concerts.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
1
.vscode/settings.json
vendored
Normal file
1
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -11,13 +11,13 @@ public sealed class CinemaConcertFolder : CinemaRootFolder
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override CollectionType? CollectionType => Data.Enums.CollectionType.music;
|
public override CollectionType? CollectionType => Data.Enums.CollectionType.musicvideos;
|
||||||
|
|
||||||
public override BaseItemKind ClientType => BaseItemKind.MusicAlbum;
|
public override BaseItemKind ClientType => BaseItemKind.MusicVideo;
|
||||||
|
|
||||||
public override ItemType ItemType => ItemType.Concert;
|
public override ItemType ItemType => ItemType.Concert;
|
||||||
|
|
||||||
internal override string ImageName => "music.png";
|
internal override string ImageName => "concert.png";
|
||||||
|
|
||||||
protected override IEnumerable<BaseItem> GetFilterItems()
|
protected override IEnumerable<BaseItem> GetFilterItems()
|
||||||
{
|
{
|
||||||
@@ -28,6 +28,6 @@ public sealed class CinemaConcertFolder : CinemaRootFolder
|
|||||||
|
|
||||||
public override bool TryCreateMediaItem(MediaSource? media, string csId, BaseItem parentFolder, [NotNullWhen(true)] out BaseItem? item)
|
public override bool TryCreateMediaItem(MediaSource? media, string csId, BaseItem parentFolder, [NotNullWhen(true)] out BaseItem? item)
|
||||||
{
|
{
|
||||||
return media.TryCreateMediaItem<CinemaMusicAlbum>(csId, parentFolder, true, out item);
|
return media.TryCreateMediaItem<Folder>(csId, parentFolder, true, out item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,11 @@ public class CinemaEpisode : Episode
|
|||||||
{
|
{
|
||||||
public sealed override string GetClientTypeName() => BaseItemKind.Episode.ToString();
|
public sealed override string GetClientTypeName() => BaseItemKind.Episode.ToString();
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
return new List<string>() { ExternalId };
|
||||||
|
}
|
||||||
|
|
||||||
protected override IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
|
protected override IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
|
||||||
{
|
{
|
||||||
var result = this.VideoGetAllItemsForMediaSources();
|
var result = this.VideoGetAllItemsForMediaSources();
|
||||||
|
|||||||
@@ -172,9 +172,6 @@ public abstract class CinemaFilterFolder : Folder
|
|||||||
{
|
{
|
||||||
Folder parentItem = LibraryManager.GetUserRootFolder();
|
Folder parentItem = LibraryManager.GetUserRootFolder();
|
||||||
folder.ParentId = parentItem.Id;
|
folder.ParentId = parentItem.Id;
|
||||||
//folder.IsRoot = true;
|
|
||||||
//if (!CinemaHost.LibraryManager.RootFolder.VirtualChildren.Contains(folder))
|
|
||||||
// CinemaHost.LibraryManager.RootFolder.AddVirtualChild(folder);
|
|
||||||
if (!parentItem.Children.Contains(folder))
|
if (!parentItem.Children.Contains(folder))
|
||||||
parentItem.AddChild(folder);
|
parentItem.AddChild(folder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ sealed class CinemaHost : IHostedService
|
|||||||
.Hide = config.HideSeriesFolder;
|
.Hide = config.HideSeriesFolder;
|
||||||
CinemaFilterFolder.CreateRootFilterFolder<CinemaAnimeFolder>(string.IsNullOrWhiteSpace(config.AnimeFolderName) ? "Anime" : config.AnimeFolderName)
|
CinemaFilterFolder.CreateRootFilterFolder<CinemaAnimeFolder>(string.IsNullOrWhiteSpace(config.AnimeFolderName) ? "Anime" : config.AnimeFolderName)
|
||||||
.Hide = config.HideAnimeFolder;
|
.Hide = config.HideAnimeFolder;
|
||||||
CinemaFilterFolder.CreateRootFilterFolder<CinemaConcertFolder>(string.IsNullOrWhiteSpace(config.MusicFolderName) ? "Music" : config.MusicFolderName)
|
CinemaFilterFolder.CreateRootFilterFolder<CinemaConcertFolder>(string.IsNullOrWhiteSpace(config.ConcertFolderName) ? "Concerts" : config.ConcertFolderName)
|
||||||
.Hide = config.HideMusicFolder;
|
.Hide = config.HideConcertFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureWebshareSession(CinemaPluginConfiguration config)
|
private void EnsureWebshareSession(CinemaPluginConfiguration config)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using CinemaLib.API;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
@@ -5,6 +6,7 @@ using MediaBrowser.Controller.Entities;
|
|||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
using MediaBrowser.Controller.Sorting;
|
using MediaBrowser.Controller.Sorting;
|
||||||
@@ -19,8 +21,9 @@ namespace Jellyfin.Plugin.Cinema;
|
|||||||
sealed class CinemaLibraryManager : ILibraryManager
|
sealed class CinemaLibraryManager : ILibraryManager
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _inner;
|
private readonly ILibraryManager _inner;
|
||||||
|
private readonly IUserDataRepository _userData;
|
||||||
|
|
||||||
public CinemaLibraryManager(CinemaInnerLibraryManager innerLibraryManager, IServiceProvider svc)
|
public CinemaLibraryManager(CinemaInnerLibraryManager innerLibraryManager, IUserDataRepository userData, IServiceProvider svc)
|
||||||
{
|
{
|
||||||
if (innerLibraryManager == null || svc == null)
|
if (innerLibraryManager == null || svc == null)
|
||||||
throw new ArgumentNullException();
|
throw new ArgumentNullException();
|
||||||
@@ -29,7 +32,7 @@ sealed class CinemaLibraryManager : ILibraryManager
|
|||||||
if (inner == null)
|
if (inner == null)
|
||||||
throw new InvalidOperationException("Original LibraryManager service not found.");
|
throw new InvalidOperationException("Original LibraryManager service not found.");
|
||||||
this._inner = inner;
|
this._inner = inner;
|
||||||
|
this._userData = userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region ILibraryManager Members
|
#region ILibraryManager Members
|
||||||
@@ -265,20 +268,46 @@ sealed class CinemaLibraryManager : ILibraryManager
|
|||||||
public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
|
public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
QueryResult<BaseItem> result = _inner.GetItemsResult(query);
|
QueryResult<BaseItem> result = _inner.GetItemsResult(query);
|
||||||
if (query.ParentId != Guid.Empty || query.OrderBy.FirstOrDefault().OrderBy == ItemSortBy.DatePlayed)
|
if (query.ParentId != Guid.Empty)
|
||||||
|
// Not a search at the root so do not involve our root folders
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
List<BaseItem> resultL = new List<BaseItem>(result.Items);
|
||||||
|
|
||||||
List<BaseItem> a = new List<BaseItem>(result.Items);
|
if (query.OrderBy.FirstOrDefault().OrderBy == ItemSortBy.DatePlayed && query.User != null)
|
||||||
foreach (BaseItem i in GetUserRootFolder().Children)
|
{
|
||||||
if (i is CinemaRootFolder root)
|
// Get Resume play items
|
||||||
|
// PERF: This may quickly become very slow
|
||||||
|
var resumePlay = _userData.GetAllUserData(query.User.InternalId)
|
||||||
|
.OrderByDescending(x => x.Played)
|
||||||
|
.Skip(query.StartIndex ?? 0)
|
||||||
|
.Take(query.Limit ?? 20);
|
||||||
|
foreach (var i in resumePlay)
|
||||||
{
|
{
|
||||||
var b = root.GetItemList(query);
|
// Note: All Cinema items override GetUserDataKeys and return ExternalId
|
||||||
if (b != null)
|
string? csId;
|
||||||
a.AddRange(b);
|
if (!CinemaQueryExtensions.TryGetCinemaIdFromExternalId(i.Key, out csId))
|
||||||
}
|
continue;
|
||||||
|
|
||||||
return new QueryResult<BaseItem>() { Items = a };
|
MediaSource? ms = Metadata.DetailAsync(csId, default).GetAwaiter().GetResult();
|
||||||
|
if (CinemaQueryExtensions.TryCreateMediaItem<Folder>(ms, csId, null, false, out BaseItem? a))
|
||||||
|
resultL.Add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Add our root folders to the search
|
||||||
|
foreach (BaseItem i in GetUserRootFolder().Children)
|
||||||
|
// Prevent duplicates as content in Anime is also elsewhere
|
||||||
|
if (i is CinemaRootFolder root && i is not CinemaAnimeFolder)
|
||||||
|
{
|
||||||
|
var b = root.GetItemList(query);
|
||||||
|
if (b != null)
|
||||||
|
resultL.AddRange(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new QueryResult<BaseItem>() { Items = resultL };
|
||||||
}
|
}
|
||||||
|
|
||||||
public LibraryOptions GetLibraryOptions(BaseItem item)
|
public LibraryOptions GetLibraryOptions(BaseItem item)
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ public class CinemaMovie : Movie
|
|||||||
{
|
{
|
||||||
public sealed override string GetClientTypeName() => BaseItemKind.Movie.ToString();
|
public sealed override string GetClientTypeName() => BaseItemKind.Movie.ToString();
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
return new List<string>() { ExternalId };
|
||||||
|
}
|
||||||
|
|
||||||
protected override IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
|
protected override IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
|
||||||
{
|
{
|
||||||
var result = this.VideoGetAllItemsForMediaSources();
|
var result = this.VideoGetAllItemsForMediaSources();
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
using CinemaLib.API;
|
|
||||||
using Jellyfin.Data.Entities;
|
|
||||||
using Jellyfin.Data.Enums;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Model.Querying;
|
|
||||||
|
|
||||||
namespace Jellyfin.Plugin.Cinema;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Music album folder item from Cinema.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class CinemaMusicAlbum : MusicAlbum
|
|
||||||
{
|
|
||||||
public sealed override string GetClientTypeName() => BaseItemKind.Series.ToString();
|
|
||||||
|
|
||||||
public override int GetChildCount(User user)
|
|
||||||
{
|
|
||||||
return base.GetChildCount(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetRecursiveChildCount(User user)
|
|
||||||
{
|
|
||||||
return base.GetRecursiveChildCount(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query)
|
|
||||||
{
|
|
||||||
return (List<BaseItem>)GetItemsInternal(query).Items;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
|
|
||||||
{
|
|
||||||
int offset = query.StartIndex ?? 0;
|
|
||||||
int limit = query.Limit ?? 0;
|
|
||||||
|
|
||||||
List<BaseItem> items = new List<BaseItem>();
|
|
||||||
QueryResult<BaseItem> result = new QueryResult<BaseItem>() { Items = items, StartIndex = offset };
|
|
||||||
|
|
||||||
FilterSortBy sortBy;
|
|
||||||
ItemOrder sortDir;
|
|
||||||
if (query.OrderBy.Count == 0)
|
|
||||||
{
|
|
||||||
sortBy = FilterSortBy.Episode;
|
|
||||||
sortDir = ItemOrder.Ascending;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
(ItemSortBy sortByJ, SortOrder sortDirJ) = query.OrderBy.First();
|
|
||||||
sortBy = sortByJ.ToCinema();
|
|
||||||
sortDir = sortDirJ == SortOrder.Ascending ? ItemOrder.Ascending : ItemOrder.Descending;
|
|
||||||
}
|
|
||||||
|
|
||||||
FilterResponse? filterRes = Metadata.ChildrenAsync(query.SearchTerm ?? "", order: sortDir, sort: sortBy, offset: offset, limit: limit).GetAwaiter().GetResult();
|
|
||||||
if (filterRes != null && filterRes.hits != null && filterRes.hits.hits != null)
|
|
||||||
{
|
|
||||||
if (filterRes.hits.total != null)
|
|
||||||
result.TotalRecordCount = (int)filterRes.hits.total.value;
|
|
||||||
foreach (var i in filterRes.hits.hits)
|
|
||||||
{
|
|
||||||
if (i._source.TryCreateMediaItem<Folder>(i._id, this, false, out BaseItem? a))
|
|
||||||
items.Add(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
36
CinemaJellyfin/CinemaMusicVideo.cs
Normal file
36
CinemaJellyfin/CinemaMusicVideo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
|
||||||
|
namespace Jellyfin.Plugin.Cinema;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Concerts folder item from Cinema.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class CinemaMusicVideo : MusicVideo
|
||||||
|
{
|
||||||
|
public sealed override string GetClientTypeName() => BaseItemKind.MusicVideo.ToString();
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
return new List<string>() { ExternalId };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
|
||||||
|
{
|
||||||
|
var result = this.VideoGetAllItemsForMediaSources();
|
||||||
|
if (result == null)
|
||||||
|
return base.GetAllItemsForMediaSources();
|
||||||
|
else
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
|
||||||
|
{
|
||||||
|
var result = this.VideoGetMediaSources(enablePathSubstitution);
|
||||||
|
if (result == null)
|
||||||
|
return base.GetMediaSources(enablePathSubstitution);
|
||||||
|
else
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@ static class CinemaQueryExtensions
|
|||||||
/// <param name="parentFolder">Jellyfin parent folder.</param>
|
/// <param name="parentFolder">Jellyfin parent folder.</param>
|
||||||
/// <param name="item">On success the created item.</param>
|
/// <param name="item">On success the created item.</param>
|
||||||
/// <returns>True on success, false otherwise.</returns>
|
/// <returns>True on success, false otherwise.</returns>
|
||||||
public static bool TryCreateMediaItem<TContainerType>(this MediaSource? media, string csId, BaseItem parentFolder, bool allowContainer, [NotNullWhen(true)] out BaseItem? item)
|
public static bool TryCreateMediaItem<TContainerType>(this MediaSource? media, string csId, BaseItem? parentFolder, bool allowContainer, [NotNullWhen(true)] out BaseItem? item)
|
||||||
where TContainerType : Folder, new()
|
where TContainerType : Folder, new()
|
||||||
{
|
{
|
||||||
if (media == null)
|
if (media == null)
|
||||||
@@ -70,12 +70,10 @@ static class CinemaQueryExtensions
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentFolderId = parentFolder.Id;
|
|
||||||
|
|
||||||
bool isNew;
|
bool isNew;
|
||||||
bool forceUpdate = false;
|
bool forceUpdate = false;
|
||||||
|
|
||||||
bool isAudio = media.is_concert ?? false;
|
bool isConcert = media.is_concert ?? false;
|
||||||
if (media.children_count != 0)
|
if (media.children_count != 0)
|
||||||
{
|
{
|
||||||
// Container
|
// Container
|
||||||
@@ -87,10 +85,9 @@ static class CinemaQueryExtensions
|
|||||||
item = GetMediaItemById<TContainerType>(csId, null, out isNew);
|
item = GetMediaItemById<TContainerType>(csId, null, out isNew);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (isAudio)
|
else if (isConcert)
|
||||||
{
|
{
|
||||||
// TODO determine if this is an AudioBook od Audio
|
item = GetMediaItemById<CinemaMusicVideo>(csId, null, out isNew);
|
||||||
item = GetMediaItemById<MediaBrowser.Controller.Entities.Audio.Audio>(csId, null, out isNew);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (media.info_labels?.mediatype == "episode")
|
else if (media.info_labels?.mediatype == "episode")
|
||||||
@@ -164,7 +161,8 @@ static class CinemaQueryExtensions
|
|||||||
hasAlbumArtists.AlbumArtists = media.info_labels?.director;
|
hasAlbumArtists.AlbumArtists = media.info_labels?.director;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.ParentId = parentFolderId;
|
if (parentFolder != null)
|
||||||
|
item.ParentId = parentFolder.Id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (item is IHasSeries hasSeries)
|
if (item is IHasSeries hasSeries)
|
||||||
|
|||||||
@@ -15,10 +15,16 @@ public sealed class CinemaSeason : Season, ICinemaChildrenCount
|
|||||||
{
|
{
|
||||||
private CinemaSubfolderHelper _helper;
|
private CinemaSubfolderHelper _helper;
|
||||||
|
|
||||||
public CinemaSeason() {
|
public CinemaSeason()
|
||||||
|
{
|
||||||
this._helper = new CinemaSubfolderHelper(this, FilterSortBy.Episode);
|
this._helper = new CinemaSubfolderHelper(this, FilterSortBy.Episode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
return new List<string>() { ExternalId };
|
||||||
|
}
|
||||||
|
|
||||||
#region ICinemaChildrenCountMembers
|
#region ICinemaChildrenCountMembers
|
||||||
|
|
||||||
public int ChildrenCount
|
public int ChildrenCount
|
||||||
@@ -27,9 +33,10 @@ public sealed class CinemaSeason : Season, ICinemaChildrenCount
|
|||||||
set => _helper.ChildrenCount = value;
|
set => _helper.ChildrenCount = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int TotalChildrenCount {
|
public int TotalChildrenCount
|
||||||
get => _helper.TotalChildrenCount;
|
{
|
||||||
set => _helper.TotalChildrenCount = value;
|
get => _helper.TotalChildrenCount;
|
||||||
|
set => _helper.TotalChildrenCount = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -15,10 +15,16 @@ public sealed class CinemaTvSeries : Series, ICinemaChildrenCount
|
|||||||
{
|
{
|
||||||
private CinemaSubfolderHelper _helper;
|
private CinemaSubfolderHelper _helper;
|
||||||
|
|
||||||
public CinemaTvSeries() {
|
public CinemaTvSeries()
|
||||||
|
{
|
||||||
this._helper = new CinemaSubfolderHelper(this, FilterSortBy.Episode);
|
this._helper = new CinemaSubfolderHelper(this, FilterSortBy.Episode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
return new List<string>() { ExternalId };
|
||||||
|
}
|
||||||
|
|
||||||
#region ICinemaChildrenCountMembers
|
#region ICinemaChildrenCountMembers
|
||||||
|
|
||||||
public int ChildrenCount
|
public int ChildrenCount
|
||||||
@@ -27,9 +33,10 @@ public sealed class CinemaTvSeries : Series, ICinemaChildrenCount
|
|||||||
set => _helper.ChildrenCount = value;
|
set => _helper.ChildrenCount = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int TotalChildrenCount {
|
public int TotalChildrenCount
|
||||||
get => _helper.TotalChildrenCount;
|
{
|
||||||
set => _helper.TotalChildrenCount = value;
|
get => _helper.TotalChildrenCount;
|
||||||
|
set => _helper.TotalChildrenCount = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -56,7 +63,7 @@ public sealed class CinemaTvSeries : Series, ICinemaChildrenCount
|
|||||||
/// Let the hack in <see cref="CinemaLibraryManager"/> find us.
|
/// Let the hack in <see cref="CinemaLibraryManager"/> find us.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override string CreatePresentationUniqueKey() => Id.ToString("N", CultureInfo.InvariantCulture);
|
public override string CreatePresentationUniqueKey() => Id.ToString("N", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query)
|
public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return (List<BaseItem>)GetItemsInternal(query).Items;
|
return (List<BaseItem>)GetItemsInternal(query).Items;
|
||||||
@@ -68,7 +75,8 @@ public sealed class CinemaTvSeries : Series, ICinemaChildrenCount
|
|||||||
|
|
||||||
// Set series identifier on all seasons
|
// Set series identifier on all seasons
|
||||||
foreach (var i in result.Items)
|
foreach (var i in result.Items)
|
||||||
if (i is CinemaSeason season) {
|
if (i is CinemaSeason season)
|
||||||
|
{
|
||||||
season.SeriesId = Id;
|
season.SeriesId = Id;
|
||||||
season.SeriesName = Name;
|
season.SeriesName = Name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ public class CinemaPluginConfiguration : BasePluginConfiguration
|
|||||||
public string AnimeFolderName { get; set; }
|
public string AnimeFolderName { get; set; }
|
||||||
public bool HideAnimeFolder { get; set; }
|
public bool HideAnimeFolder { get; set; }
|
||||||
|
|
||||||
public string MusicFolderName { get; set; }
|
public string ConcertFolderName { get; set; }
|
||||||
public bool HideMusicFolder { get; set; }
|
public bool HideConcertFolder { get; set; }
|
||||||
|
|
||||||
public string? WebshareUser { get; set; }
|
public string? WebshareUser { get; set; }
|
||||||
public string? WebsharePassword { get; set; }
|
public string? WebsharePassword { get; set; }
|
||||||
|
|||||||
@@ -40,12 +40,12 @@
|
|||||||
<br />
|
<br />
|
||||||
|
|
||||||
<div class="inputContainer">
|
<div class="inputContainer">
|
||||||
<input is="emby-input" type="text" id="musicFolderName" label="Music Folder Name" />
|
<input is="emby-input" type="text" id="concertFolderName" label="Concerts Folder Name" />
|
||||||
<div class="fieldDescription">Custom name for the Cinema Music root folder.</div>
|
<div class="fieldDescription">Custom name for the Cinema Concerts root folder.</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="checkboxContainer">
|
<label class="checkboxContainer">
|
||||||
<input is="emby-checkbox" type="checkbox" id="hideMusicFolder" />
|
<input is="emby-checkbox" type="checkbox" id="hideConcertFolder" />
|
||||||
<span>Hide the Cinema Music root folder.</span>
|
<span>Hide the Cinema Concerts root folder.</span>
|
||||||
</label>
|
</label>
|
||||||
<div class="verticalSection verticalSection-extrabottompadding">
|
<div class="verticalSection verticalSection-extrabottompadding">
|
||||||
<h2>Webshare Account</h2>
|
<h2>Webshare Account</h2>
|
||||||
@@ -101,14 +101,14 @@
|
|||||||
}));
|
}));
|
||||||
document.querySelector('#hideAnimeFolder').checked = config.HideAnimeFolder;
|
document.querySelector('#hideAnimeFolder').checked = config.HideAnimeFolder;
|
||||||
|
|
||||||
var musicFolderName = document.querySelector('#musicFolderName');
|
var concertFolderName = document.querySelector('#concertFolderName');
|
||||||
if (config.MusicFolderName)
|
if (config.ConcertFolderName)
|
||||||
musicFolderName.value = config.MusicFolderName;
|
concertFolderName.value = config.ConcertFolderName;
|
||||||
musicFolderName.dispatchEvent(new Event('change', {
|
concertFolderName.dispatchEvent(new Event('change', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: false
|
cancelable: false
|
||||||
}));
|
}));
|
||||||
document.querySelector('#hideMusicFolder').checked = config.HideMusicFolder;
|
document.querySelector('#hideConcertFolder').checked = config.HideConcertFolder;
|
||||||
|
|
||||||
var webshareUser = document.querySelector('#webshareUser');
|
var webshareUser = document.querySelector('#webshareUser');
|
||||||
if (config.WebshareUser)
|
if (config.WebshareUser)
|
||||||
@@ -140,8 +140,8 @@
|
|||||||
config.HideSeriesFolder = document.querySelector('#hideSeriesFolder').checked;
|
config.HideSeriesFolder = document.querySelector('#hideSeriesFolder').checked;
|
||||||
config.AnimeFolderName = document.querySelector('#animeFolderName').value;
|
config.AnimeFolderName = document.querySelector('#animeFolderName').value;
|
||||||
config.HideAnimeFolder = document.querySelector('#hideAnimeFolder').checked;
|
config.HideAnimeFolder = document.querySelector('#hideAnimeFolder').checked;
|
||||||
config.MusicFolderName = document.querySelector('#musicFolderName').value;
|
config.ConcertFolderName = document.querySelector('#concertFolderName').value;
|
||||||
config.HideMusicFolder = document.querySelector('#hideMusicFolder').checked;
|
config.HideConcertFolder = document.querySelector('#hideConcertFolder').checked;
|
||||||
|
|
||||||
config.WebshareUser = document.querySelector('#webshareUser').value;
|
config.WebshareUser = document.querySelector('#webshareUser').value;
|
||||||
config.WebsharePassword = document.querySelector('#websharePassword').value;
|
config.WebsharePassword = document.querySelector('#websharePassword').value;
|
||||||
|
|||||||
@@ -37,22 +37,27 @@ public class Metadata
|
|||||||
if (limit == 0 || limit > MaxPageLimit)
|
if (limit == 0 || limit > MaxPageLimit)
|
||||||
limit = MaxPageLimit;
|
limit = MaxPageLimit;
|
||||||
|
|
||||||
bool noSearchTerms = expression.Trim().Length == 0;
|
bool noSearchTerms = expression.Trim().Length == 0;
|
||||||
string filterName;
|
string filterName;
|
||||||
string sortS = ToString(sort);
|
string sortS = ToString(sort);
|
||||||
if (sort == FilterSortBy.Title) {
|
if (sort == FilterSortBy.Title)
|
||||||
filterName = "startsWithSimple";
|
{
|
||||||
sortS = "";
|
filterName = "startsWithSimple";
|
||||||
} else if (noSearchTerms) {
|
sortS = "";
|
||||||
filterName = "all";
|
}
|
||||||
} else {
|
else if (noSearchTerms)
|
||||||
filterName = "search";
|
{
|
||||||
}
|
filterName = "all";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filterName = "search";
|
||||||
|
}
|
||||||
|
|
||||||
UriBuilder uri = new UriBuilder(new Uri(ApiFilter, filterName));
|
UriBuilder uri = new UriBuilder(new Uri(ApiFilter, filterName));
|
||||||
string orderS = order == ItemOrder.Ascending ? "asc" : "desc";
|
string orderS = order == ItemOrder.Ascending ? "asc" : "desc";
|
||||||
uri.Query = $"?access_token={AccessToken}&value={Uri.EscapeDataString(expression)}&type={ToString(type)}&from={offset.ToString()}&size={limit.ToString()}"
|
uri.Query = $"?access_token={AccessToken}&value={Uri.EscapeDataString(expression)}&type={ToString(type)}&from={offset.ToString()}&size={limit.ToString()}"
|
||||||
+ (sortS.Length != 0 ? $"&order={ToString(order)}&sort={sortS}" : "");
|
+ (sortS.Length != 0 ? $"&order={ToString(order)}&sort={sortS}" : "");
|
||||||
|
|
||||||
FilterResponse? result = await Program._http.GetFromJsonAsync<FilterResponse>(uri.Uri, CreateFilterJsonOptions(), cancel);
|
FilterResponse? result = await Program._http.GetFromJsonAsync<FilterResponse>(uri.Uri, CreateFilterJsonOptions(), cancel);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
@@ -81,6 +86,24 @@ public class Metadata
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets detail info about in item.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">Item identifier.</param>
|
||||||
|
/// <param name="cancel">Asynchronous cancellation.</param>
|
||||||
|
/// <returns>Media info.</returns>
|
||||||
|
public async static Task<MediaSource?> DetailAsync(string id, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
if (id == null || id.Length == 0)
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
|
||||||
|
Uri uri = new Uri(new Uri(ApiRoot, "media/"), id);
|
||||||
|
MediaSource? result = await Program._http.GetFromJsonAsync<MediaSource>(uri, CreateFilterJsonOptions(), cancel);
|
||||||
|
if (result != null)
|
||||||
|
result = FixDetailResponse(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets available streams for the given media.
|
/// Gets available streams for the given media.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -160,17 +183,26 @@ public class Metadata
|
|||||||
if (i._source == null)
|
if (i._source == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (i._source.cast != null)
|
FixDetailResponse(i._source);
|
||||||
foreach (Cast j in i._source.cast)
|
}
|
||||||
j.thumbnail = FixImageUrl(j.thumbnail);
|
|
||||||
|
|
||||||
if (i._source.i18n_info_labels != null)
|
return res;
|
||||||
foreach (InfoLabelI18n j in i._source.i18n_info_labels) {
|
}
|
||||||
if (j.art != null) {
|
|
||||||
j.art.poster = FixImageUrl(j.art.poster);
|
private static MediaSource FixDetailResponse(MediaSource res)
|
||||||
j.art.fanart = FixImageUrl(j.art.fanart);
|
{
|
||||||
}
|
if (res.cast != null)
|
||||||
}
|
foreach (Cast j in res.cast)
|
||||||
|
j.thumbnail = FixImageUrl(j.thumbnail);
|
||||||
|
|
||||||
|
if (res.i18n_info_labels != null)
|
||||||
|
foreach (InfoLabelI18n j in res.i18n_info_labels)
|
||||||
|
{
|
||||||
|
if (j.art != null)
|
||||||
|
{
|
||||||
|
j.art.poster = FixImageUrl(j.art.poster);
|
||||||
|
j.art.fanart = FixImageUrl(j.art.fanart);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -178,7 +210,8 @@ public class Metadata
|
|||||||
|
|
||||||
private static string FixImageUrl(string url)
|
private static string FixImageUrl(string url)
|
||||||
{
|
{
|
||||||
if (url != null && !url.StartsWith("http")) {
|
if (url != null && !url.StartsWith("http"))
|
||||||
|
{
|
||||||
if (url.StartsWith("//"))
|
if (url.StartsWith("//"))
|
||||||
url = "https:" + url;
|
url = "https:" + url;
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user