mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-11-02 18:47:11 -05:00 
			
		
		
		
	Finishing the repositories's rework
This commit is contained in:
		
							parent
							
								
									2ad4c89806
								
							
						
					
					
						commit
						81f555ca7e
					
				@ -93,9 +93,10 @@ namespace Kyoo.Models
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				if (Type != StreamType.Subtitle)
 | 
									if (Type != StreamType.Subtitle)
 | 
				
			||||||
					return null;
 | 
										return null;
 | 
				
			||||||
				string slug = $"/subtitle/{Episode.Slug}.{Language ?? ID.ToString()}";
 | 
					
 | 
				
			||||||
				if (IsForced)
 | 
									string slug = string.IsNullOrEmpty(Language) 
 | 
				
			||||||
					slug += "-forced";
 | 
										? ID.ToString()
 | 
				
			||||||
 | 
										: $"{Episode.Slug}.{Language}{(IsForced ? "-forced" : "")}";
 | 
				
			||||||
				switch (Codec)
 | 
									switch (Codec)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					case "ass":
 | 
										case "ass":
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
		public override async Task<ICollection<Collection>> Search(string query)
 | 
							public override async Task<ICollection<Collection>> Search(string query)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Collections
 | 
								return await _database.Collections
 | 
				
			||||||
				.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
 | 
									.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		public override Task<Episode> Get(string slug)
 | 
							public override Task<Episode> Get(string slug)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Match match = Regex.Match(slug, @"(<show>.*)-s(<season>\d*)-e(<episode>\d*)");
 | 
								Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)-e(?<episode>\d*)");
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			if (!match.Success)
 | 
								if (!match.Success)
 | 
				
			||||||
				return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == slug);
 | 
									return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == slug);
 | 
				
			||||||
@ -57,7 +57,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
		public override async Task<ICollection<Episode>> Search(string query)
 | 
							public override async Task<ICollection<Episode>> Search(string query)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Episodes
 | 
								return await _database.Episodes
 | 
				
			||||||
				.Where(x => EF.Functions.Like(x.Title, $"%{query}%"))
 | 
									.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -21,10 +21,10 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ICollection<Genre>> Search(string query)
 | 
							public override async Task<ICollection<Genre>> Search(string query)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Genres
 | 
								return await _database.Genres
 | 
				
			||||||
				.Where(genre => EF.Functions.Like(genre.Name, $"%{query}%"))
 | 
									.Where(genre => EF.Functions.ILike(genre.Name, $"%{query}%"))
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -57,7 +57,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			return Task.CompletedTask;
 | 
								return Task.CompletedTask;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task Delete(Genre obj)
 | 
							public override async Task Delete(Genre obj)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
 | 
				
			|||||||
@ -9,54 +9,41 @@ using Microsoft.EntityFrameworkCore;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Kyoo.Controllers
 | 
					namespace Kyoo.Controllers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class LibraryRepository : ILibraryRepository
 | 
						public class LibraryRepository : LocalRepository<Library>, ILibraryRepository
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		private readonly DatabaseContext _database;
 | 
							private readonly DatabaseContext _database;
 | 
				
			||||||
		private readonly IProviderRepository _providers;
 | 
							private readonly IProviderRepository _providers;
 | 
				
			||||||
 | 
							protected override Expression<Func<Library, object>> DefaultSort => x => x.ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public LibraryRepository(DatabaseContext database, IProviderRepository providers)
 | 
							public LibraryRepository(DatabaseContext database, IProviderRepository providers) : base(database)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database = database;
 | 
								_database = database;
 | 
				
			||||||
			_providers = providers;
 | 
								_providers = providers;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Dispose()
 | 
					
 | 
				
			||||||
 | 
							public override void Dispose()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database.Dispose();
 | 
								_database.Dispose();
 | 
				
			||||||
 | 
								_providers.Dispose();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public ValueTask DisposeAsync()
 | 
							public override async ValueTask DisposeAsync()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return _database.DisposeAsync();
 | 
								await _database.DisposeAsync();
 | 
				
			||||||
 | 
								await _providers.DisposeAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Task<Library> Get(int id)
 | 
							public override async Task<ICollection<Library>> Search(string query)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.Libraries.FirstOrDefaultAsync(x => x.ID == id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public Task<Library> Get(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.Libraries.FirstOrDefaultAsync(x => x.Slug == slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<ICollection<Library>> Search(string query)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Libraries
 | 
								return await _database.Libraries
 | 
				
			||||||
				.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
 | 
									.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ICollection<Library>> GetAll(Expression<Func<Library, bool>> where = null, 
 | 
							public override async Task<Library> Create(Library obj)
 | 
				
			||||||
			Sort<Library> sort = default,
 | 
					 | 
				
			||||||
			Pagination limit = default)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Libraries.ToListAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<Library> Create(Library obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -74,7 +61,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			catch (DbUpdateException ex)
 | 
								catch (DbUpdateException ex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				_database.DiscardChanges();
 | 
									_database.DiscardChanges();
 | 
				
			||||||
				if (Helper.IsDuplicateException(ex))
 | 
									if (IsDuplicateException(ex))
 | 
				
			||||||
					throw new DuplicatedItemException($"Trying to insert a duplicated library (slug {obj.Slug} already exists).");
 | 
										throw new DuplicatedItemException($"Trying to insert a duplicated library (slug {obj.Slug} already exists).");
 | 
				
			||||||
				throw;
 | 
									throw;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -82,65 +69,14 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			return obj;
 | 
								return obj;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<Library> CreateIfNotExists(Library obj)
 | 
							protected override async Task Validate(Library obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (obj == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			Library old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
			if (old != null)
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			try
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				return await Create(obj);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			catch (DuplicatedItemException)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
				if (old == null)
 | 
					 | 
				
			||||||
					throw new SystemException("Unknown database state.");
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<Library> Edit(Library edited, bool resetOld)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (edited == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(edited));
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			Library old = await Get(edited.Name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (old == null)
 | 
					 | 
				
			||||||
				throw new ItemNotFound($"No library found with the name {edited.Name}.");
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			if (resetOld)
 | 
					 | 
				
			||||||
				Utility.Nullify(old);
 | 
					 | 
				
			||||||
			Utility.Merge(old, edited);
 | 
					 | 
				
			||||||
			await Validate(old);
 | 
					 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
					 | 
				
			||||||
			return old;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private async Task Validate(Library obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj.ProviderLinks != null)
 | 
								if (obj.ProviderLinks != null)
 | 
				
			||||||
				foreach (ProviderLink link in obj.ProviderLinks)
 | 
									foreach (ProviderLink link in obj.ProviderLinks)
 | 
				
			||||||
					link.Provider = await _providers.CreateIfNotExists(link.Provider);
 | 
										link.Provider = await _providers.CreateIfNotExists(link.Provider);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task Delete(int id)
 | 
							public override async Task Delete(Library obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Library obj = await Get(id);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Library obj = await Get(slug);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task Delete(Library obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -154,23 +90,5 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
					_database.Entry(entry).State = EntityState.Deleted;
 | 
										_database.Entry(entry).State = EntityState.Deleted;
 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
								await _database.SaveChangesAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<Library> objs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (Library obj in objs)
 | 
					 | 
				
			||||||
				await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<int> ids)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (int id in ids)
 | 
					 | 
				
			||||||
				await Delete(id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<string> slugs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (string slug in slugs)
 | 
					 | 
				
			||||||
				await Delete(slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -9,53 +9,40 @@ using Microsoft.EntityFrameworkCore;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Kyoo.Controllers
 | 
					namespace Kyoo.Controllers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class PeopleRepository : IPeopleRepository
 | 
						public class PeopleRepository : LocalRepository<People>, IPeopleRepository
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		private readonly DatabaseContext _database;
 | 
							private readonly DatabaseContext _database;
 | 
				
			||||||
		private readonly IProviderRepository _providers;
 | 
							private readonly IProviderRepository _providers;
 | 
				
			||||||
 | 
							protected override Expression<Func<People, object>> DefaultSort => x => x.Name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public PeopleRepository(DatabaseContext database, IProviderRepository providers)
 | 
							public PeopleRepository(DatabaseContext database, IProviderRepository providers) : base(database)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database = database;
 | 
								_database = database;
 | 
				
			||||||
			_providers = providers;
 | 
								_providers = providers;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Dispose()
 | 
					
 | 
				
			||||||
 | 
							public override void Dispose()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database.Dispose();
 | 
								_database.Dispose();
 | 
				
			||||||
 | 
								_providers.Dispose();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public ValueTask DisposeAsync()
 | 
							public override async ValueTask DisposeAsync()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return _database.DisposeAsync();
 | 
								await _database.DisposeAsync();
 | 
				
			||||||
 | 
								await _providers.DisposeAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Task<People> Get(int id)
 | 
							public override async Task<ICollection<People>> Search(string query)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.Peoples.FirstOrDefaultAsync(x => x.ID == id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public Task<People> Get(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.Peoples.FirstOrDefaultAsync(x => x.Slug == slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<ICollection<People>> Search(string query)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Peoples
 | 
								return await _database.Peoples
 | 
				
			||||||
				.Where(people => EF.Functions.Like(people.Name, $"%{query}%"))
 | 
									.Where(people => EF.Functions.ILike(people.Name, $"%{query}%"))
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ICollection<People>> GetAll(Expression<Func<People, bool>> where = null, 
 | 
							public override async Task<People> Create(People obj)
 | 
				
			||||||
			Sort<People> sort = default,
 | 
					 | 
				
			||||||
			Pagination limit = default)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Peoples.ToListAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<People> Create(People obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -73,7 +60,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			catch (DbUpdateException ex)
 | 
								catch (DbUpdateException ex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				_database.DiscardChanges();
 | 
									_database.DiscardChanges();
 | 
				
			||||||
				if (Helper.IsDuplicateException(ex))
 | 
									if (IsDuplicateException(ex))
 | 
				
			||||||
					throw new DuplicatedItemException($"Trying to insert a duplicated people (slug {obj.Slug} already exists).");
 | 
										throw new DuplicatedItemException($"Trying to insert a duplicated people (slug {obj.Slug} already exists).");
 | 
				
			||||||
				throw;
 | 
									throw;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -81,65 +68,14 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			return obj;
 | 
								return obj;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<People> CreateIfNotExists(People obj)
 | 
							protected override async Task Validate(People obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (obj == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			People old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
			if (old != null)
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			try
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				return await Create(obj);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			catch (DuplicatedItemException)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
				if (old == null)
 | 
					 | 
				
			||||||
					throw new SystemException("Unknown database state.");
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<People> Edit(People edited, bool resetOld)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (edited == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(edited));
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			People old = await Get(edited.Slug);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (old == null)
 | 
					 | 
				
			||||||
				throw new ItemNotFound($"No people found with the slug {edited.Slug}.");
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			if (resetOld)
 | 
					 | 
				
			||||||
				Utility.Nullify(old);
 | 
					 | 
				
			||||||
			Utility.Merge(old, edited);
 | 
					 | 
				
			||||||
			await Validate(old);
 | 
					 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
					 | 
				
			||||||
			return old;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		private async Task Validate(People obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj.ExternalIDs != null)
 | 
								if (obj.ExternalIDs != null)
 | 
				
			||||||
				foreach (MetadataID link in obj.ExternalIDs)
 | 
									foreach (MetadataID link in obj.ExternalIDs)
 | 
				
			||||||
					link.Provider = await _providers.CreateIfNotExists(link.Provider);
 | 
										link.Provider = await _providers.CreateIfNotExists(link.Provider);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public async Task Delete(int id)
 | 
							public override async Task Delete(People obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			People obj = await Get(id);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			People obj = await Get(slug);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(People obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -153,23 +89,5 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
					_database.Entry(link).State = EntityState.Deleted;
 | 
										_database.Entry(link).State = EntityState.Deleted;
 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
								await _database.SaveChangesAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<People> objs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (People obj in objs)
 | 
					 | 
				
			||||||
				await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<int> ids)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (int id in ids)
 | 
					 | 
				
			||||||
				await Delete(id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<string> slugs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (string slug in slugs)
 | 
					 | 
				
			||||||
				await Delete(slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -9,52 +9,26 @@ using Microsoft.EntityFrameworkCore;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Kyoo.Controllers
 | 
					namespace Kyoo.Controllers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class ProviderRepository : IProviderRepository
 | 
						public class ProviderRepository : LocalRepository<ProviderID>, IProviderRepository
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		private readonly DatabaseContext _database;
 | 
							private readonly DatabaseContext _database;
 | 
				
			||||||
 | 
							protected override Expression<Func<ProviderID, object>> DefaultSort => x => x.Slug;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public ProviderRepository(DatabaseContext database)
 | 
							public ProviderRepository(DatabaseContext database) : base(database)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database = database;
 | 
								_database = database;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Dispose()
 | 
							public override async Task<ICollection<ProviderID>> Search(string query)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			_database.Dispose();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public ValueTask DisposeAsync()
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.DisposeAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task<ProviderID> Get(int id)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Providers.FirstOrDefaultAsync(x => x.ID == id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task<ProviderID> Get(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Providers.FirstOrDefaultAsync(x => x.Name == slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<ICollection<ProviderID>> Search(string query)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Providers
 | 
								return await _database.Providers
 | 
				
			||||||
				.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
 | 
									.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ICollection<ProviderID>> GetAll(Expression<Func<ProviderID, bool>> where = null, 
 | 
							public override async Task<ProviderID> Create(ProviderID obj)
 | 
				
			||||||
			Sort<ProviderID> sort = default,
 | 
					 | 
				
			||||||
			Pagination limit = default)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Providers.ToListAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<ProviderID> Create(ProviderID obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -68,7 +42,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			catch (DbUpdateException ex)
 | 
								catch (DbUpdateException ex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				_database.DiscardChanges();
 | 
									_database.DiscardChanges();
 | 
				
			||||||
				if (Helper.IsDuplicateException(ex))
 | 
									if (IsDuplicateException(ex))
 | 
				
			||||||
					throw new DuplicatedItemException($"Trying to insert a duplicated provider (name {obj.Name} already exists).");
 | 
										throw new DuplicatedItemException($"Trying to insert a duplicated provider (name {obj.Name} already exists).");
 | 
				
			||||||
				throw;
 | 
									throw;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -76,57 +50,12 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			return obj;
 | 
								return obj;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public async Task<ProviderID> CreateIfNotExists(ProviderID obj)
 | 
							protected override Task Validate(ProviderID ressource)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								return Task.CompletedTask;
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			ProviderID old = await Get(obj.Name);
 | 
					 | 
				
			||||||
			if (old != null)
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			try
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				return await Create(obj);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			catch (DuplicatedItemException)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				old = await Get(obj.Name);
 | 
					 | 
				
			||||||
				if (old == null)
 | 
					 | 
				
			||||||
					throw new SystemException("Unknown database state.");
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ProviderID> Edit(ProviderID edited, bool resetOld)
 | 
							public override async Task Delete(ProviderID obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (edited == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(edited));
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			ProviderID old = await Get(edited.Name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (old == null)
 | 
					 | 
				
			||||||
				throw new ItemNotFound($"No provider found with the name {edited.Name}.");
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			if (resetOld)
 | 
					 | 
				
			||||||
				Utility.Nullify(old);
 | 
					 | 
				
			||||||
			Utility.Merge(old, edited);
 | 
					 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
					 | 
				
			||||||
			return old;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(int id)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			ProviderID obj = await Get(id);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			ProviderID obj = await Get(slug);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task Delete(ProviderID obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -135,23 +64,5 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			// TODO handle ExternalID deletion when they refer to this providerID.
 | 
								// TODO handle ExternalID deletion when they refer to this providerID.
 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
								await _database.SaveChangesAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<ProviderID> objs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (ProviderID obj in objs)
 | 
					 | 
				
			||||||
				await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<int> ids)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (int id in ids)
 | 
					 | 
				
			||||||
				await Delete(id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<string> slugs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (string slug in slugs)
 | 
					 | 
				
			||||||
				await Delete(slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -2,6 +2,7 @@ using System;
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Kyoo.Models;
 | 
					using Kyoo.Models;
 | 
				
			||||||
using Kyoo.Models.Exceptions;
 | 
					using Kyoo.Models.Exceptions;
 | 
				
			||||||
@ -9,44 +10,44 @@ using Microsoft.EntityFrameworkCore;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Kyoo.Controllers
 | 
					namespace Kyoo.Controllers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class SeasonRepository : ISeasonRepository
 | 
						public class SeasonRepository : LocalRepository<Season>, ISeasonRepository
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		private readonly DatabaseContext _database;
 | 
							private readonly DatabaseContext _database;
 | 
				
			||||||
		private readonly IProviderRepository _providers;
 | 
							private readonly IProviderRepository _providers;
 | 
				
			||||||
		private readonly IEpisodeRepository _episodes;
 | 
							private readonly IEpisodeRepository _episodes;
 | 
				
			||||||
 | 
							protected override Expression<Func<Season, object>> DefaultSort => x => x.SeasonNumber;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public SeasonRepository(DatabaseContext database, IProviderRepository providers, IEpisodeRepository episodes)
 | 
							public SeasonRepository(DatabaseContext database, IProviderRepository providers, IEpisodeRepository episodes)
 | 
				
			||||||
 | 
								: base(database)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database = database;
 | 
								_database = database;
 | 
				
			||||||
			_providers = providers;
 | 
								_providers = providers;
 | 
				
			||||||
			_episodes = episodes;
 | 
								_episodes = episodes;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Dispose()
 | 
					
 | 
				
			||||||
 | 
							public override void Dispose()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database.Dispose();
 | 
								_database.Dispose();
 | 
				
			||||||
 | 
								_providers.Dispose();
 | 
				
			||||||
 | 
								_episodes.Dispose();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public ValueTask DisposeAsync()
 | 
							public override async ValueTask DisposeAsync()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return _database.DisposeAsync();
 | 
								await _database.DisposeAsync();
 | 
				
			||||||
 | 
								await _providers.DisposeAsync();
 | 
				
			||||||
 | 
								await _episodes.DisposeAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Task<Season> Get(int id)
 | 
							public override Task<Season> Get(string slug)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return _database.Seasons.FirstOrDefaultAsync(x => x.ID == id);
 | 
								Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)");
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
		public Task<Season> Get(string slug)
 | 
								if (!match.Success)
 | 
				
			||||||
		{
 | 
									throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
 | 
				
			||||||
			int index = slug.IndexOf("-s", StringComparison.Ordinal);
 | 
								return Get(match.Groups["show"].Value, int.Parse(match.Groups["season"].Value));
 | 
				
			||||||
			if (index == -1)
 | 
					 | 
				
			||||||
				throw new InvalidOperationException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
 | 
					 | 
				
			||||||
			string showSlug = slug.Substring(0, index);
 | 
					 | 
				
			||||||
			if (!int.TryParse(slug.Substring(index + 2), out int seasonNumber))
 | 
					 | 
				
			||||||
				throw new InvalidOperationException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
 | 
					 | 
				
			||||||
			return Get(showSlug, seasonNumber);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public Task<Season> Get(string showSlug, int seasonNumber)
 | 
							public Task<Season> Get(string showSlug, int seasonNumber)
 | 
				
			||||||
@ -55,22 +56,15 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			                                                        && x.SeasonNumber == seasonNumber);
 | 
								                                                        && x.SeasonNumber == seasonNumber);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ICollection<Season>> Search(string query)
 | 
							public override async Task<ICollection<Season>> Search(string query)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Seasons
 | 
								return await _database.Seasons
 | 
				
			||||||
				.Where(x => EF.Functions.Like(x.Title, $"%{query}%"))
 | 
									.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public async Task<ICollection<Season>> GetAll(Expression<Func<Season, bool>> where = null, 
 | 
							public override async Task<Season> Create(Season obj)
 | 
				
			||||||
			Sort<Season> sort = default,
 | 
					 | 
				
			||||||
			Pagination limit = default)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Seasons.ToListAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<Season> Create(Season obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -88,7 +82,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			catch (DbUpdateException ex)
 | 
								catch (DbUpdateException ex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				_database.DiscardChanges();
 | 
									_database.DiscardChanges();
 | 
				
			||||||
				if (Helper.IsDuplicateException(ex))
 | 
									if (IsDuplicateException(ex))
 | 
				
			||||||
					throw new DuplicatedItemException($"Trying to insert a duplicated season (slug {obj.Slug} already exists).");
 | 
										throw new DuplicatedItemException($"Trying to insert a duplicated season (slug {obj.Slug} already exists).");
 | 
				
			||||||
				throw;
 | 
									throw;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -96,47 +90,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			return obj;
 | 
								return obj;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<Season> CreateIfNotExists(Season obj)
 | 
							protected override async Task Validate(Season obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (obj == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			Season old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
			if (old != null)
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			try
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				return await Create(obj);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			catch (DuplicatedItemException)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
				if (old == null)
 | 
					 | 
				
			||||||
					throw new SystemException("Unknown database state.");
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<Season> Edit(Season edited, bool resetOld)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (edited == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(edited));
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			Season old = await Get(edited.Slug);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (old == null)
 | 
					 | 
				
			||||||
				throw new ItemNotFound($"No season found with the slug {edited.Slug}.");
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			if (resetOld)
 | 
					 | 
				
			||||||
				Utility.Nullify(old);
 | 
					 | 
				
			||||||
			Utility.Merge(old, edited);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			await Validate(old);
 | 
					 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
					 | 
				
			||||||
			return old;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private async Task Validate(Season obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj.ShowID <= 0)
 | 
								if (obj.ShowID <= 0)
 | 
				
			||||||
				throw new InvalidOperationException($"Can't store a season not related to any show (showID: {obj.ShowID}).");
 | 
									throw new InvalidOperationException($"Can't store a season not related to any show (showID: {obj.ShowID}).");
 | 
				
			||||||
@ -158,25 +112,13 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			return await _database.Seasons.Where(x => x.Show.Slug == showSlug).ToListAsync();
 | 
								return await _database.Seasons.Where(x => x.Show.Slug == showSlug).ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public async Task Delete(int id)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Season obj = await Get(id);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Season obj = await Get(slug);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(string showSlug, int seasonNumber)
 | 
							public async Task Delete(string showSlug, int seasonNumber)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Season obj = await Get(showSlug, seasonNumber);
 | 
								Season obj = await Get(showSlug, seasonNumber);
 | 
				
			||||||
			await Delete(obj);
 | 
								await Delete(obj);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task Delete(Season obj)
 | 
							public override async Task Delete(Season obj)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -192,23 +134,5 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			if (obj.Episodes != null)
 | 
								if (obj.Episodes != null)
 | 
				
			||||||
				await _episodes.DeleteRange(obj.Episodes);
 | 
									await _episodes.DeleteRange(obj.Episodes);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<Season> objs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (Season obj in objs)
 | 
					 | 
				
			||||||
				await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<int> ids)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (int id in ids)
 | 
					 | 
				
			||||||
				await Delete(id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<string> slugs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (string slug in slugs)
 | 
					 | 
				
			||||||
				await Delete(slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -3,14 +3,13 @@ using System.Collections.Generic;
 | 
				
			|||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Kyoo.CommonApi;
 | 
					 | 
				
			||||||
using Kyoo.Models;
 | 
					using Kyoo.Models;
 | 
				
			||||||
using Kyoo.Models.Exceptions;
 | 
					using Kyoo.Models.Exceptions;
 | 
				
			||||||
using Microsoft.EntityFrameworkCore;
 | 
					using Microsoft.EntityFrameworkCore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Kyoo.Controllers
 | 
					namespace Kyoo.Controllers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class ShowRepository : IShowRepository
 | 
						public class ShowRepository : LocalRepository<Show>, IShowRepository
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		private readonly DatabaseContext _database;
 | 
							private readonly DatabaseContext _database;
 | 
				
			||||||
		private readonly IStudioRepository _studios;
 | 
							private readonly IStudioRepository _studios;
 | 
				
			||||||
@ -19,6 +18,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
		private readonly IProviderRepository _providers;
 | 
							private readonly IProviderRepository _providers;
 | 
				
			||||||
		private readonly ISeasonRepository _seasons;
 | 
							private readonly ISeasonRepository _seasons;
 | 
				
			||||||
		private readonly IEpisodeRepository _episodes;
 | 
							private readonly IEpisodeRepository _episodes;
 | 
				
			||||||
 | 
							protected override Expression<Func<Show, object>> DefaultSort => x => x.Title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public ShowRepository(DatabaseContext database,
 | 
							public ShowRepository(DatabaseContext database,
 | 
				
			||||||
			IStudioRepository studios,
 | 
								IStudioRepository studios,
 | 
				
			||||||
@ -27,6 +27,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			IProviderRepository providers, 
 | 
								IProviderRepository providers, 
 | 
				
			||||||
			ISeasonRepository seasons, 
 | 
								ISeasonRepository seasons, 
 | 
				
			||||||
			IEpisodeRepository episodes)
 | 
								IEpisodeRepository episodes)
 | 
				
			||||||
 | 
								: base(database)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database = database;
 | 
								_database = database;
 | 
				
			||||||
			_studios = studios;
 | 
								_studios = studios;
 | 
				
			||||||
@ -37,69 +38,38 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			_episodes = episodes;
 | 
								_episodes = episodes;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Dispose()
 | 
							public override void Dispose()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database.Dispose();
 | 
								_database.Dispose();
 | 
				
			||||||
			_studios.Dispose();
 | 
								_studios.Dispose();
 | 
				
			||||||
 | 
								_people.Dispose();
 | 
				
			||||||
 | 
								_genres.Dispose();
 | 
				
			||||||
 | 
								_providers.Dispose();
 | 
				
			||||||
 | 
								_seasons.Dispose();
 | 
				
			||||||
 | 
								_episodes.Dispose();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async ValueTask DisposeAsync()
 | 
							public override async ValueTask DisposeAsync()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			await Task.WhenAll(_database.DisposeAsync().AsTask(), _studios.DisposeAsync().AsTask());
 | 
								await _database.DisposeAsync();
 | 
				
			||||||
 | 
								await _studios.DisposeAsync();
 | 
				
			||||||
 | 
								await _people.DisposeAsync();
 | 
				
			||||||
 | 
								await _genres.DisposeAsync();
 | 
				
			||||||
 | 
								await _providers.DisposeAsync();
 | 
				
			||||||
 | 
								await _seasons.DisposeAsync();
 | 
				
			||||||
 | 
								await _episodes.DisposeAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Task<Show> Get(int id)
 | 
							public override async Task<ICollection<Show>> Search(string query)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.Shows.FirstOrDefaultAsync(x => x.ID == id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public Task<Show> Get(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.Shows.FirstOrDefaultAsync(x => x.Slug == slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public Task<Show> GetByPath(string path)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.Shows.FirstOrDefaultAsync(x => x.Path == path);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<ICollection<Show>> Search(string query)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Shows
 | 
								return await _database.Shows
 | 
				
			||||||
				.FromSqlInterpolated($@"SELECT * FROM Shows WHERE 'Shows.Title' LIKE {$"%{query}%"}
 | 
									.Where(x => EF.Functions.ILike(x.Title, $"%{query}%") 
 | 
				
			||||||
			                                           OR 'Shows.Aliases' LIKE {$"%{query}%"}")
 | 
									            /*|| EF.Functions.ILike(x.Aliases, $"%{query}%")*/)
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ICollection<Show>> GetAll(Expression<Func<Show, bool>> where = null, 
 | 
							public override async Task<Show> Create(Show obj)
 | 
				
			||||||
			Sort<Show> sort = default,
 | 
					 | 
				
			||||||
			Pagination limit = default)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			IQueryable<Show> query = _database.Shows;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (where != null)
 | 
					 | 
				
			||||||
				query = query.Where(where);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			Expression<Func<Show, object>> sortKey = sort.Key ?? (x => x.Title);
 | 
					 | 
				
			||||||
			query = sort.Descendant ? query.OrderByDescending(sortKey) : query.OrderBy(sortKey);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (limit.AfterID != 0)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Show after = await Get(limit.AfterID);
 | 
					 | 
				
			||||||
				object afterObj = sortKey.Compile()(after);
 | 
					 | 
				
			||||||
				query = query.Where(Expression.Lambda<Func<Show, bool>>(
 | 
					 | 
				
			||||||
					ApiHelper.StringCompatibleExpression(Expression.GreaterThan, sortKey.Body, Expression.Constant(afterObj)),
 | 
					 | 
				
			||||||
					(ParameterExpression)((MemberExpression)sortKey.Body).Expression
 | 
					 | 
				
			||||||
				));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (limit.Count > 0)
 | 
					 | 
				
			||||||
				query = query.Take(limit.Count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return await query.ToListAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<Show> Create(Show obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -123,7 +93,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			catch (DbUpdateException ex)
 | 
								catch (DbUpdateException ex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				_database.DiscardChanges();
 | 
									_database.DiscardChanges();
 | 
				
			||||||
				if (Helper.IsDuplicateException(ex))
 | 
									if (IsDuplicateException(ex))
 | 
				
			||||||
					throw new DuplicatedItemException($"Trying to insert a duplicated show (slug {obj.Slug} already exists).");
 | 
										throw new DuplicatedItemException($"Trying to insert a duplicated show (slug {obj.Slug} already exists).");
 | 
				
			||||||
				throw;
 | 
									throw;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -131,46 +101,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			return obj;
 | 
								return obj;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public async Task<Show> CreateIfNotExists(Show obj)
 | 
							protected override async Task Validate(Show obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (obj == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			Show old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
			if (old != null)
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			try
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				return await Create(obj);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			catch (DuplicatedItemException)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
				if (old == null)
 | 
					 | 
				
			||||||
					throw new SystemException("Unknown database state.");
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<Show> Edit(Show edited, bool resetOld)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (edited == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(edited));
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			Show old = await Get(edited.Slug);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (old == null)
 | 
					 | 
				
			||||||
				throw new ItemNotFound($"No show found with the slug {edited.Slug}.");
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			if (resetOld)
 | 
					 | 
				
			||||||
				Utility.Nullify(old);
 | 
					 | 
				
			||||||
			Utility.Merge(old, edited);
 | 
					 | 
				
			||||||
			await Validate(old);
 | 
					 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
					 | 
				
			||||||
			return old;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		private async Task Validate(Show obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj.Studio != null)
 | 
								if (obj.Studio != null)
 | 
				
			||||||
				obj.Studio = await _studios.CreateIfNotExists(obj.Studio);
 | 
									obj.Studio = await _studios.CreateIfNotExists(obj.Studio);
 | 
				
			||||||
@ -211,19 +142,7 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			await _database.SaveChangesAsync();
 | 
								await _database.SaveChangesAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public async Task Delete(int id)
 | 
							public override async Task Delete(Show obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Show obj = await Get(id);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Show obj = await Get(slug);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task Delete(Show obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -258,23 +177,5 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			if (obj.Episodes != null) 
 | 
								if (obj.Episodes != null) 
 | 
				
			||||||
				await _episodes.DeleteRange(obj.Episodes);
 | 
									await _episodes.DeleteRange(obj.Episodes);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<Show> objs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (Show obj in objs)
 | 
					 | 
				
			||||||
				await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<int> ids)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (int id in ids)
 | 
					 | 
				
			||||||
				await Delete(id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<string> slugs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (string slug in slugs)
 | 
					 | 
				
			||||||
				await Delete(slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -9,52 +9,26 @@ using Microsoft.EntityFrameworkCore;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Kyoo.Controllers
 | 
					namespace Kyoo.Controllers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class StudioRepository : IStudioRepository
 | 
						public class StudioRepository : LocalRepository<Studio>, IStudioRepository
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		private readonly DatabaseContext _database;
 | 
							private readonly DatabaseContext _database;
 | 
				
			||||||
 | 
							protected override Expression<Func<Studio, object>> DefaultSort => x => x.Name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public StudioRepository(DatabaseContext database)
 | 
							public StudioRepository(DatabaseContext database) : base(database)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database = database;
 | 
								_database = database;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public void Dispose()
 | 
							public override async Task<ICollection<Studio>> Search(string query)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			_database.Dispose();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public ValueTask DisposeAsync()
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return _database.DisposeAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task<Studio> Get(int id)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Studios.FirstOrDefaultAsync(x => x.ID == id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task<Studio> Get(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Studios.FirstOrDefaultAsync(x => x.Slug == slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<ICollection<Studio>> Search(string query)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return await _database.Studios
 | 
								return await _database.Studios
 | 
				
			||||||
				.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
 | 
									.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
 | 
				
			||||||
				.Take(20)
 | 
									.Take(20)
 | 
				
			||||||
				.ToListAsync();
 | 
									.ToListAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ICollection<Studio>> GetAll(Expression<Func<Studio, bool>> where = null, 
 | 
							public override async Task<Studio> Create(Studio obj)
 | 
				
			||||||
			Sort<Studio> sort = default,
 | 
					 | 
				
			||||||
			Pagination limit = default)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Studios.ToListAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<Studio> Create(Studio obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -68,64 +42,19 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			catch (DbUpdateException ex)
 | 
								catch (DbUpdateException ex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				_database.DiscardChanges();
 | 
									_database.DiscardChanges();
 | 
				
			||||||
				if (Helper.IsDuplicateException(ex))
 | 
									if (IsDuplicateException(ex))
 | 
				
			||||||
					throw new DuplicatedItemException($"Trying to insert a duplicated studio (slug {obj.Slug} already exists).");
 | 
										throw new DuplicatedItemException($"Trying to insert a duplicated studio (slug {obj.Slug} already exists).");
 | 
				
			||||||
				throw;
 | 
									throw;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return obj;
 | 
								return obj;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<Studio> CreateIfNotExists(Studio obj)
 | 
							protected override Task Validate(Studio ressource)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								return Task.CompletedTask;
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			Studio old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
			if (old != null)
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			try
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				return await Create(obj);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			catch (DuplicatedItemException)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				old = await Get(obj.Slug);
 | 
					 | 
				
			||||||
				if (old == null)
 | 
					 | 
				
			||||||
					throw new SystemException("Unknown database state.");
 | 
					 | 
				
			||||||
				return old;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public async Task<Studio> Edit(Studio edited, bool resetOld)
 | 
							public override async Task Delete(Studio obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (edited == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(edited));
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			Studio old = await Get(edited.Name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (old == null)
 | 
					 | 
				
			||||||
				throw new ItemNotFound($"No studio found with the name {edited.Name}.");
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			if (resetOld)
 | 
					 | 
				
			||||||
				Utility.Nullify(old);
 | 
					 | 
				
			||||||
			Utility.Merge(old, edited);
 | 
					 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
					 | 
				
			||||||
			return old;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(int id)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Studio obj = await Get(id);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Studio obj = await Get(slug);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task Delete(Studio obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -137,23 +66,5 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
				show.StudioID = null;
 | 
									show.StudioID = null;
 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
								await _database.SaveChangesAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<Studio> objs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (Studio obj in objs)
 | 
					 | 
				
			||||||
				await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<int> ids)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (int id in ids)
 | 
					 | 
				
			||||||
				await Delete(id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<string> slugs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (string slug in slugs)
 | 
					 | 
				
			||||||
				await Delete(slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Kyoo.Models;
 | 
					using Kyoo.Models;
 | 
				
			||||||
using Kyoo.Models.Exceptions;
 | 
					using Kyoo.Models.Exceptions;
 | 
				
			||||||
@ -8,34 +9,39 @@ using Microsoft.EntityFrameworkCore;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Kyoo.Controllers
 | 
					namespace Kyoo.Controllers
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class TrackRepository : ITrackRepository
 | 
						public class TrackRepository : LocalRepository<Track>, ITrackRepository
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		private readonly DatabaseContext _database;
 | 
							private readonly DatabaseContext _database;
 | 
				
			||||||
 | 
							protected override Expression<Func<Track, object>> DefaultSort => x => x.ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public TrackRepository(DatabaseContext database)
 | 
							public TrackRepository(DatabaseContext database) : base(database)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database = database;
 | 
								_database = database;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Dispose()
 | 
							public override Task<Track> Get(string slug)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_database.Dispose();
 | 
								Match match = Regex.Match(slug,
 | 
				
			||||||
 | 
									@"(?<show>.*)-s(?<season>\d*)-e(?<episode>\d*).(?<language>.{0,3})(?<forced>-forced)?(\..*)?");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!match.Success)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (int.TryParse(slug, out int id))
 | 
				
			||||||
 | 
										return Get(id);
 | 
				
			||||||
 | 
									throw new ArgumentException("Invalid track slug. Format: {episodeSlug}.{language}[-forced][.{extension}]");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public ValueTask DisposeAsync()
 | 
								string showSlug = match.Groups["show"].Value;
 | 
				
			||||||
		{
 | 
								int seasonNumber = int.Parse(match.Groups["season"].Value);
 | 
				
			||||||
			return _database.DisposeAsync();
 | 
								int episodeNumber = int.Parse(match.Groups["episode"].Value);
 | 
				
			||||||
		}
 | 
								string language = match.Groups["language"].Value;
 | 
				
			||||||
		
 | 
								bool forced = match.Groups["forced"].Success;
 | 
				
			||||||
		public async Task<Track> Get(int id)
 | 
								return _database.Tracks.FirstOrDefaultAsync(x => x.Episode.Show.Slug == showSlug
 | 
				
			||||||
		{
 | 
								                                                 && x.Episode.SeasonNumber == seasonNumber
 | 
				
			||||||
			return await _database.Tracks.FirstOrDefaultAsync(x => x.ID == id);
 | 
								                                                 && x.Episode.EpisodeNumber == episodeNumber
 | 
				
			||||||
		}
 | 
								                                                 && x.Language == language
 | 
				
			||||||
		
 | 
								                                                 && x.IsForced == forced);
 | 
				
			||||||
		public Task<Track> Get(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw new InvalidOperationException("Tracks do not support the get by slug method.");
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Task<Track> Get(int episodeID, string languageTag, bool isForced)
 | 
							public Task<Track> Get(int episodeID, string languageTag, bool isForced)
 | 
				
			||||||
@ -45,19 +51,12 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			                                                       && x.IsForced == isForced);
 | 
								                                                       && x.IsForced == isForced);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Task<ICollection<Track>> Search(string query)
 | 
							public override Task<ICollection<Track>> Search(string query)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			throw new InvalidOperationException("Tracks do not support the search method.");
 | 
								throw new InvalidOperationException("Tracks do not support the search method.");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public async Task<ICollection<Track>> GetAll(Expression<Func<Track, bool>> where = null, 
 | 
							public override async Task<Track> Create(Track obj)
 | 
				
			||||||
			Sort<Track> sort = default,
 | 
					 | 
				
			||||||
			Pagination limit = default)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return await _database.Tracks.ToListAsync();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task<Track> Create(Track obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -74,48 +73,19 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			catch (DbUpdateException ex)
 | 
								catch (DbUpdateException ex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				_database.DiscardChanges();
 | 
									_database.DiscardChanges();
 | 
				
			||||||
				if (Helper.IsDuplicateException(ex))
 | 
									if (IsDuplicateException(ex))
 | 
				
			||||||
					throw new DuplicatedItemException($"Trying to insert a duplicated track (slug {obj.Slug} already exists).");
 | 
										throw new DuplicatedItemException($"Trying to insert a duplicated track (slug {obj.Slug} already exists).");
 | 
				
			||||||
				throw;
 | 
									throw;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return obj;
 | 
								return obj;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public Task<Track> CreateIfNotExists(Track obj)
 | 
							protected override Task Validate(Track ressource)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return Create(obj);
 | 
								return Task.CompletedTask;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		public async Task<Track> Edit(Track edited, bool resetOld)
 | 
							public override async Task Delete(Track obj)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (edited == null)
 | 
					 | 
				
			||||||
				throw new ArgumentNullException(nameof(edited));
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			Track old = await Get(edited.ID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (old == null)
 | 
					 | 
				
			||||||
				throw new ItemNotFound($"No track found with the ID {edited.ID}.");
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			if (resetOld)
 | 
					 | 
				
			||||||
				Utility.Nullify(old);
 | 
					 | 
				
			||||||
			Utility.Merge(old, edited);
 | 
					 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
					 | 
				
			||||||
			return old;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(int id)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Track obj = await Get(id);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		public async Task Delete(string slug)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Track obj = await Get(slug);
 | 
					 | 
				
			||||||
			await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task Delete(Track obj)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (obj == null)
 | 
								if (obj == null)
 | 
				
			||||||
				throw new ArgumentNullException(nameof(obj));
 | 
									throw new ArgumentNullException(nameof(obj));
 | 
				
			||||||
@ -123,23 +93,5 @@ namespace Kyoo.Controllers
 | 
				
			|||||||
			_database.Entry(obj).State = EntityState.Deleted;
 | 
								_database.Entry(obj).State = EntityState.Deleted;
 | 
				
			||||||
			await _database.SaveChangesAsync();
 | 
								await _database.SaveChangesAsync();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<Track> objs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (Track obj in objs)
 | 
					 | 
				
			||||||
				await Delete(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<int> ids)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (int id in ids)
 | 
					 | 
				
			||||||
				await Delete(id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		public async Task DeleteRange(IEnumerable<string> slugs)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			foreach (string slug in slugs)
 | 
					 | 
				
			||||||
				await Delete(slug);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user