mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-04 06:04:39 -04:00
Making edit routes kinda work
This commit is contained in:
parent
5229e319b1
commit
41cabdd1b5
@ -43,7 +43,7 @@ namespace Kyoo.Controllers
|
||||
Task<Season> GetSeason(string showSlug, int seasonNumber);
|
||||
Task<Episode> GetEpisode(string showSlug, int seasonNumber, int episodeNumber);
|
||||
Task<Episode> GetMovieEpisode(string movieSlug);
|
||||
Task<Track> GetTrack(string slug, StreamType type = StreamType.Unknow);
|
||||
Task<Track> GetTrack(string slug, StreamType type = StreamType.Unknown);
|
||||
Task<Genre> GetGenre(string slug);
|
||||
Task<Studio> GetStudio(string slug);
|
||||
Task<People> GetPeople(string slug);
|
||||
|
@ -95,20 +95,7 @@ namespace Kyoo.Controllers
|
||||
|
||||
|
||||
Task<T> Create([NotNull] T obj);
|
||||
Task<T> CreateIfNotExists([NotNull] T obj);
|
||||
async Task<T> CreateIfNotExists([NotNull] T obj, bool silentFail)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await CreateIfNotExists(obj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (!silentFail)
|
||||
throw;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Task<T> CreateIfNotExists([NotNull] T obj, bool silentFail = false);
|
||||
Task<T> Edit([NotNull] T edited, bool resetOld);
|
||||
|
||||
Task Delete(int id);
|
||||
@ -147,7 +134,7 @@ namespace Kyoo.Controllers
|
||||
|
||||
public interface ITrackRepository : IRepository<Track>
|
||||
{
|
||||
Task<Track> Get(string slug, StreamType type = StreamType.Unknow);
|
||||
Task<Track> Get(string slug, StreamType type = StreamType.Unknown);
|
||||
}
|
||||
|
||||
public interface ILibraryRepository : IRepository<Library> { }
|
||||
|
@ -110,7 +110,7 @@ namespace Kyoo.Controllers
|
||||
return EpisodeRepository.Get(showID, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
public Task<Track> GetTrack(string slug, StreamType type = StreamType.Unknow)
|
||||
public Task<Track> GetTrack(string slug, StreamType type = StreamType.Unknown)
|
||||
{
|
||||
return TrackRepository.Get(slug, type);
|
||||
}
|
||||
|
6
Kyoo.Common/Models/Attributes/EditableRelation.cs
Normal file
6
Kyoo.Common/Models/Attributes/EditableRelation.cs
Normal file
@ -0,0 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Models.Attributes
|
||||
{
|
||||
public class EditableRelation : Attribute { }
|
||||
}
|
@ -23,7 +23,7 @@ namespace Kyoo.Models
|
||||
public int Runtime { get; set; } //This runtime variable should be in minutes
|
||||
|
||||
[JsonIgnore] public string Poster { get; set; }
|
||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
[EditableRelation] public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
[JsonIgnore] public virtual IEnumerable<Track> Tracks { get; set; }
|
||||
|
||||
|
@ -10,7 +10,7 @@ namespace Kyoo.Models
|
||||
public string Name { get; set; }
|
||||
public IEnumerable<string> Paths { get; set; }
|
||||
|
||||
public virtual IEnumerable<ProviderID> Providers { get; set; }
|
||||
[EditableRelation] public virtual IEnumerable<ProviderID> Providers { get; set; }
|
||||
|
||||
[JsonIgnore] public virtual IEnumerable<Show> Shows { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Collection> Collections { get; set; }
|
||||
|
@ -9,9 +9,9 @@ namespace Kyoo.Models
|
||||
public string Slug { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Poster { get; set; }
|
||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
[EditableRelation] public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
[JsonReadOnly] public virtual IEnumerable<PeopleRole> Roles { get; set; }
|
||||
[EditableRelation] [JsonReadOnly] public virtual IEnumerable<PeopleRole> Roles { get; set; }
|
||||
|
||||
public People() {}
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace Kyoo.Models
|
||||
public int? Year { get; set; }
|
||||
|
||||
[JsonIgnore] public string Poster { get; set; }
|
||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
[EditableRelation] public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
[JsonIgnore] public virtual Show Show { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
|
||||
|
@ -28,9 +28,9 @@ namespace Kyoo.Models
|
||||
|
||||
|
||||
[JsonIgnore] public int? StudioID { get; set; }
|
||||
[JsonReadOnly] public virtual Studio Studio { get; set; }
|
||||
[JsonReadOnly] public virtual IEnumerable<Genre> Genres { get; set; }
|
||||
[JsonReadOnly] public virtual IEnumerable<PeopleRole> People { get; set; }
|
||||
[EditableRelation] [JsonReadOnly] public virtual Studio Studio { get; set; }
|
||||
[EditableRelation] [JsonReadOnly] public virtual IEnumerable<Genre> Genres { get; set; }
|
||||
[EditableRelation] [JsonReadOnly] public virtual IEnumerable<PeopleRole> People { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Season> Seasons { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Library> Libraries { get; set; }
|
||||
|
@ -8,7 +8,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public enum StreamType
|
||||
{
|
||||
Unknow = 0,
|
||||
Unknown = 0,
|
||||
Video = 1,
|
||||
Audio = 2,
|
||||
Subtitle = 3,
|
||||
|
@ -102,9 +102,8 @@ namespace Kyoo
|
||||
|
||||
Type type = typeof(T);
|
||||
IEnumerable<PropertyInfo> properties = type.GetProperties()
|
||||
.Where(x => x.CanRead
|
||||
&& x.CanWrite
|
||||
&& Attribute.GetCustomAttribute(x, typeof(NotMergableAttribute)) == null);
|
||||
.Where(x => x.CanRead && x.CanWrite
|
||||
&& Attribute.GetCustomAttribute(x, typeof(NotMergableAttribute)) == null);
|
||||
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
@ -114,11 +113,7 @@ namespace Kyoo
|
||||
: null;
|
||||
|
||||
if (value?.Equals(defaultValue) == false)
|
||||
{
|
||||
if (value is IEnumerable enumerable && !(value is string))
|
||||
value = RunGenericMethod(typeof(Enumerable), "ToList", GetEnumerableType(enumerable), value);
|
||||
property.SetValue(first, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (first is IOnMerge merge)
|
||||
|
@ -13,7 +13,19 @@ using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class JsonPropertySelector : CamelCasePropertyNamesContractResolver
|
||||
public class JsonPropertyIgnorer : CamelCasePropertyNamesContractResolver
|
||||
{
|
||||
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
||||
{
|
||||
JsonProperty property = base.CreateProperty(member, memberSerialization);
|
||||
|
||||
property.ShouldSerialize = i => member.GetCustomAttribute<JsonReadOnly>(true) == null;
|
||||
property.ShouldDeserialize = i => member.GetCustomAttribute<JsonIgnore>(true) == null;
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonPropertySelector : JsonPropertyIgnorer
|
||||
{
|
||||
private readonly Dictionary<Type, HashSet<string>> _ignored;
|
||||
private readonly Dictionary<Type, HashSet<string>> _forceSerialize;
|
||||
@ -60,20 +72,9 @@ namespace Kyoo.Controllers
|
||||
JsonProperty property = base.CreateProperty(member, memberSerialization);
|
||||
|
||||
if (IsSerializationForced(property.DeclaringType, property.PropertyName))
|
||||
{
|
||||
property.ShouldSerialize = i => true;
|
||||
property.Ignored = false;
|
||||
}
|
||||
else if (IsIgnored(property.DeclaringType, property.PropertyName))
|
||||
{
|
||||
property.ShouldSerialize = i => false;
|
||||
property.Ignored = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
property.ShouldSerialize = i => member.GetCustomAttribute<JsonReadOnly>(true) == null;
|
||||
property.ShouldDeserialize = i => member.GetCustomAttribute<JsonIgnore>(true) == null;
|
||||
}
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.CommonApi;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Attributes;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
@ -118,25 +119,32 @@ namespace Kyoo.Controllers
|
||||
return obj;
|
||||
}
|
||||
|
||||
public virtual async Task<T> CreateIfNotExists(T obj)
|
||||
public virtual async Task<T> CreateIfNotExists(T obj, bool silentFail = false)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
T old = await Get(obj.Slug);
|
||||
if (old != null)
|
||||
return old;
|
||||
try
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
T old = await Get(obj.Slug);
|
||||
if (old != null)
|
||||
return old;
|
||||
|
||||
return await Create(obj);
|
||||
}
|
||||
catch (DuplicatedItemException)
|
||||
{
|
||||
old = await Get(obj.Slug);
|
||||
T old = await Get(obj!.Slug);
|
||||
if (old == null)
|
||||
throw new SystemException("Unknown database state.");
|
||||
return old;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (silentFail)
|
||||
return default;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<T> Edit(T edited, bool resetOld)
|
||||
@ -152,14 +160,17 @@ namespace Kyoo.Controllers
|
||||
if (old == null)
|
||||
throw new ItemNotFound($"No resource found with the ID {edited.ID}.");
|
||||
|
||||
IEnumerable<NavigationEntry> relations = Database.Entry(old).Collections
|
||||
.Concat(Database.Entry(old).Navigations);
|
||||
foreach (NavigationEntry navigation in relations)
|
||||
if (navigation.Metadata.PropertyInfo.GetCustomAttribute<EditableRelation>() != null)
|
||||
await navigation.LoadAsync();
|
||||
|
||||
if (resetOld)
|
||||
Utility.Nullify(old);
|
||||
Utility.Complete(old, edited);
|
||||
// TODO Validation set values & setting values trigger a change round in the OEM. A change round should only be triggered if the item is actually different.
|
||||
await Validate(old);
|
||||
// TODO should fix this, new links & deleted links should be kept.
|
||||
// TODO The changetracker has trash values now & values can't be listed before the validation (exception is thrown)
|
||||
foreach (EntityEntry x in Database.ChangeTracker.Entries().Where(x => x.Entity != old))
|
||||
x.State = EntityState.Detached;
|
||||
await Database.SaveChangesAsync();
|
||||
return old;
|
||||
}
|
||||
@ -168,7 +179,7 @@ namespace Kyoo.Controllers
|
||||
Database.ChangeTracker.LazyLoadingEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected virtual Task Validate(T resource)
|
||||
{
|
||||
if (string.IsNullOrEmpty(resource.Slug))
|
||||
@ -298,13 +309,13 @@ namespace Kyoo.Controllers
|
||||
.Then(x => item.ID = x.ID);
|
||||
}
|
||||
|
||||
Task<T> IRepository<T>.CreateIfNotExists(T item)
|
||||
Task<T> IRepository<T>.CreateIfNotExists(T item, bool silentFail)
|
||||
{
|
||||
TInternal obj = item as TInternal ?? new TInternal();
|
||||
if (!(item is TInternal))
|
||||
Utility.Assign(obj, item);
|
||||
|
||||
return CreateIfNotExists(obj).Cast<T>()
|
||||
return CreateIfNotExists(obj, silentFail).Cast<T>()
|
||||
.Then(x => item.ID = x.ID);
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,13 @@ namespace Kyoo.Controllers
|
||||
}
|
||||
|
||||
public override Task<LibraryItem> Create(LibraryItem obj) => throw new InvalidOperationException();
|
||||
public override Task<LibraryItem> CreateIfNotExists(LibraryItem obj) => throw new InvalidOperationException();
|
||||
|
||||
public override Task<LibraryItem> CreateIfNotExists(LibraryItem obj, bool silentFail = false)
|
||||
{
|
||||
if (silentFail)
|
||||
return Task.FromResult<LibraryItem>(default);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
public override Task<LibraryItem> Edit(LibraryItem obj, bool reset) => throw new InvalidOperationException();
|
||||
protected override Task Validate(LibraryItem resource) => throw new InvalidOperationException();
|
||||
public override Task Delete(int id) => throw new InvalidOperationException();
|
||||
|
@ -75,7 +75,8 @@ namespace Kyoo.Controllers
|
||||
query = $"%{query}%";
|
||||
return await _database.Shows
|
||||
.Where(x => EF.Functions.ILike(x.Title, query)
|
||||
/*|| x.Aliases.Any(y => EF.Functions.ILike(y, query))*/) // NOT TRANSLATABLE.
|
||||
|| EF.Functions.ILike(x.Slug, query)
|
||||
/*|| x.Aliases.Any(y => EF.Functions.ILike(y, query))*/) // NOT TRANSLATABLE.
|
||||
.Take(20)
|
||||
.ToListAsync<Show>();
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace Kyoo.Controllers
|
||||
await _database.DisposeAsync();
|
||||
}
|
||||
|
||||
public Task<Track> Get(string slug, StreamType type = StreamType.Unknow)
|
||||
public Task<Track> Get(string slug, StreamType type = StreamType.Unknown)
|
||||
{
|
||||
Match match = Regex.Match(slug,
|
||||
@"(?<show>.*)-s(?<season>\d+)e(?<episode>\d+)\.(?<language>.{0,3})(?<forced>-forced)?(\..*)?");
|
||||
@ -57,7 +57,7 @@ namespace Kyoo.Controllers
|
||||
string language = match.Groups["language"].Value;
|
||||
bool forced = match.Groups["forced"].Success;
|
||||
|
||||
if (type == StreamType.Unknow)
|
||||
if (type == StreamType.Unknown)
|
||||
{
|
||||
return _database.Tracks.FirstOrDefaultAsync(x => x.Episode.Show.Slug == showSlug
|
||||
&& x.Episode.SeasonNumber == seasonNumber
|
||||
|
@ -55,7 +55,7 @@ namespace Kyoo.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(10, cancellationToken);
|
||||
await Task.Delay(1000, cancellationToken);
|
||||
QueueScheduledTasks();
|
||||
}
|
||||
}
|
||||
@ -63,8 +63,8 @@ namespace Kyoo.Controllers
|
||||
|
||||
private void QueueScheduledTasks()
|
||||
{
|
||||
List<string> tasksToQueue = _tasks.Where(x => x.scheduledDate <= DateTime.Now)
|
||||
.Select(x => x.task.Slug).ToList();
|
||||
IEnumerable<string> tasksToQueue = _tasks.Where(x => x.scheduledDate <= DateTime.Now)
|
||||
.Select(x => x.task.Slug);
|
||||
foreach (string task in tasksToQueue)
|
||||
StartTask(task);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ namespace Kyoo.Controllers.TranscoderLink
|
||||
for (int i = 0; i < arrayLength; i++)
|
||||
{
|
||||
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
|
||||
if (stream!.Type != StreamType.Unknow)
|
||||
if (stream!.Type != StreamType.Unknown)
|
||||
{
|
||||
tracks[j] = new Track(stream);
|
||||
j++;
|
||||
|
@ -6,7 +6,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class LibraryDE : Library
|
||||
{
|
||||
[JsonIgnore] [NotMergable] public virtual ICollection<ProviderLink> ProviderLinks { get; set; }
|
||||
[EditableRelation] [JsonIgnore] [NotMergable] public virtual ICollection<ProviderLink> ProviderLinks { get; set; }
|
||||
[ExpressionRewrite(nameof(ProviderLinks), nameof(ProviderLink.Provider))]
|
||||
public override IEnumerable<ProviderID> Providers
|
||||
{
|
||||
|
@ -6,7 +6,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class ShowDE : Show
|
||||
{
|
||||
[JsonReadOnly] [NotMergable] public virtual ICollection<GenreLink> GenreLinks { get; set; }
|
||||
[EditableRelation] [JsonReadOnly] [NotMergable] public virtual ICollection<GenreLink> GenreLinks { get; set; }
|
||||
[ExpressionRewrite(nameof(GenreLinks), nameof(GenreLink.Genre))]
|
||||
public override IEnumerable<Genre> Genres
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ namespace Kyoo
|
||||
});
|
||||
|
||||
services.AddControllers()
|
||||
.AddNewtonsoftJson(x => x.SerializerSettings.ContractResolver = new JsonPropertySelector());
|
||||
.AddNewtonsoftJson(x => x.SerializerSettings.ContractResolver = new JsonPropertyIgnorer());
|
||||
services.AddHttpClient();
|
||||
|
||||
services.AddDbContext<DatabaseContext>(options =>
|
||||
|
Loading…
x
Reference in New Issue
Block a user