mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-08 02:34:16 -04: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)
|
||||
return null;
|
||||
string slug = $"/subtitle/{Episode.Slug}.{Language ?? ID.ToString()}";
|
||||
if (IsForced)
|
||||
slug += "-forced";
|
||||
|
||||
string slug = string.IsNullOrEmpty(Language)
|
||||
? ID.ToString()
|
||||
: $"{Episode.Slug}.{Language}{(IsForced ? "-forced" : "")}";
|
||||
switch (Codec)
|
||||
{
|
||||
case "ass":
|
||||
|
@ -22,7 +22,7 @@ namespace Kyoo.Controllers
|
||||
public override async Task<ICollection<Collection>> Search(string query)
|
||||
{
|
||||
return await _database.Collections
|
||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
||||
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace Kyoo.Controllers
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
return await _database.Episodes
|
||||
.Where(x => EF.Functions.Like(x.Title, $"%{query}%"))
|
||||
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
|
||||
.Take(20)
|
||||
.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
|
||||
.Where(genre => EF.Functions.Like(genre.Name, $"%{query}%"))
|
||||
.Where(genre => EF.Functions.ILike(genre.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
@ -57,7 +57,7 @@ namespace Kyoo.Controllers
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task Delete(Genre obj)
|
||||
public override async Task Delete(Genre obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
@ -9,54 +9,41 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class LibraryRepository : ILibraryRepository
|
||||
public class LibraryRepository : LocalRepository<Library>, ILibraryRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
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;
|
||||
_providers = providers;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
public override void 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)
|
||||
{
|
||||
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)
|
||||
public override async Task<ICollection<Library>> Search(string query)
|
||||
{
|
||||
return await _database.Libraries
|
||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
||||
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Library>> GetAll(Expression<Func<Library, bool>> where = null,
|
||||
Sort<Library> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return await _database.Libraries.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<Library> Create(Library obj)
|
||||
public override async Task<Library> Create(Library obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -74,73 +61,22 @@ namespace Kyoo.Controllers
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_database.DiscardChanges();
|
||||
if (Helper.IsDuplicateException(ex))
|
||||
if (IsDuplicateException(ex))
|
||||
throw new DuplicatedItemException($"Trying to insert a duplicated library (slug {obj.Slug} already exists).");
|
||||
throw;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public async Task<Library> CreateIfNotExists(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)
|
||||
protected override async Task Validate(Library obj)
|
||||
{
|
||||
if (obj.ProviderLinks != null)
|
||||
foreach (ProviderLink link in obj.ProviderLinks)
|
||||
link.Provider = await _providers.CreateIfNotExists(link.Provider);
|
||||
}
|
||||
|
||||
public async Task Delete(int id)
|
||||
{
|
||||
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)
|
||||
public override async Task Delete(Library obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -154,23 +90,5 @@ namespace Kyoo.Controllers
|
||||
_database.Entry(entry).State = EntityState.Deleted;
|
||||
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
|
||||
{
|
||||
public class PeopleRepository : IPeopleRepository
|
||||
public class PeopleRepository : LocalRepository<People>, IPeopleRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
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;
|
||||
_providers = providers;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
|
||||
public override void 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)
|
||||
{
|
||||
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)
|
||||
public override async Task<ICollection<People>> Search(string query)
|
||||
{
|
||||
return await _database.Peoples
|
||||
.Where(people => EF.Functions.Like(people.Name, $"%{query}%"))
|
||||
.Where(people => EF.Functions.ILike(people.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<People>> GetAll(Expression<Func<People, bool>> where = null,
|
||||
Sort<People> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return await _database.Peoples.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<People> Create(People obj)
|
||||
public override async Task<People> Create(People obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -73,7 +60,7 @@ namespace Kyoo.Controllers
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_database.DiscardChanges();
|
||||
if (Helper.IsDuplicateException(ex))
|
||||
if (IsDuplicateException(ex))
|
||||
throw new DuplicatedItemException($"Trying to insert a duplicated people (slug {obj.Slug} already exists).");
|
||||
throw;
|
||||
}
|
||||
@ -81,65 +68,14 @@ namespace Kyoo.Controllers
|
||||
return obj;
|
||||
}
|
||||
|
||||
public async Task<People> CreateIfNotExists(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)
|
||||
protected override async Task Validate(People obj)
|
||||
{
|
||||
if (obj.ExternalIDs != null)
|
||||
foreach (MetadataID link in obj.ExternalIDs)
|
||||
link.Provider = await _providers.CreateIfNotExists(link.Provider);
|
||||
}
|
||||
|
||||
public async Task Delete(int id)
|
||||
{
|
||||
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)
|
||||
public override async Task Delete(People obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -153,23 +89,5 @@ namespace Kyoo.Controllers
|
||||
_database.Entry(link).State = EntityState.Deleted;
|
||||
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
|
||||
{
|
||||
public class ProviderRepository : IProviderRepository
|
||||
public class ProviderRepository : LocalRepository<ProviderID>, IProviderRepository
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_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)
|
||||
public override async Task<ICollection<ProviderID>> Search(string query)
|
||||
{
|
||||
return await _database.Providers
|
||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
||||
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<ProviderID>> GetAll(Expression<Func<ProviderID, bool>> where = null,
|
||||
Sort<ProviderID> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return await _database.Providers.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ProviderID> Create(ProviderID obj)
|
||||
public override async Task<ProviderID> Create(ProviderID obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -68,7 +42,7 @@ namespace Kyoo.Controllers
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_database.DiscardChanges();
|
||||
if (Helper.IsDuplicateException(ex))
|
||||
if (IsDuplicateException(ex))
|
||||
throw new DuplicatedItemException($"Trying to insert a duplicated provider (name {obj.Name} already exists).");
|
||||
throw;
|
||||
}
|
||||
@ -76,57 +50,12 @@ namespace Kyoo.Controllers
|
||||
return obj;
|
||||
}
|
||||
|
||||
public async Task<ProviderID> CreateIfNotExists(ProviderID obj)
|
||||
protected override Task Validate(ProviderID ressource)
|
||||
{
|
||||
if (obj == null)
|
||||
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;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<ProviderID> Edit(ProviderID edited, bool resetOld)
|
||||
{
|
||||
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)
|
||||
public override async Task Delete(ProviderID obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -135,23 +64,5 @@ namespace Kyoo.Controllers
|
||||
// TODO handle ExternalID deletion when they refer to this providerID.
|
||||
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.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
@ -9,44 +10,44 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class SeasonRepository : ISeasonRepository
|
||||
public class SeasonRepository : LocalRepository<Season>, ISeasonRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IProviderRepository _providers;
|
||||
private readonly IEpisodeRepository _episodes;
|
||||
protected override Expression<Func<Season, object>> DefaultSort => x => x.SeasonNumber;
|
||||
|
||||
|
||||
public SeasonRepository(DatabaseContext database, IProviderRepository providers, IEpisodeRepository episodes)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
_providers = providers;
|
||||
_episodes = episodes;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_database.Dispose();
|
||||
_providers.Dispose();
|
||||
_episodes.Dispose();
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
return _database.DisposeAsync();
|
||||
}
|
||||
|
||||
public Task<Season> Get(int id)
|
||||
{
|
||||
return _database.Seasons.FirstOrDefaultAsync(x => x.ID == id);
|
||||
await _database.DisposeAsync();
|
||||
await _providers.DisposeAsync();
|
||||
await _episodes.DisposeAsync();
|
||||
}
|
||||
|
||||
public Task<Season> Get(string slug)
|
||||
public override Task<Season> Get(string slug)
|
||||
{
|
||||
int index = slug.IndexOf("-s", StringComparison.Ordinal);
|
||||
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);
|
||||
Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)");
|
||||
|
||||
if (!match.Success)
|
||||
throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
|
||||
return Get(match.Groups["show"].Value, int.Parse(match.Groups["season"].Value));
|
||||
}
|
||||
|
||||
public Task<Season> Get(string showSlug, int seasonNumber)
|
||||
@ -55,22 +56,15 @@ namespace Kyoo.Controllers
|
||||
&& x.SeasonNumber == seasonNumber);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Season>> Search(string query)
|
||||
public override async Task<ICollection<Season>> Search(string query)
|
||||
{
|
||||
return await _database.Seasons
|
||||
.Where(x => EF.Functions.Like(x.Title, $"%{query}%"))
|
||||
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Season>> GetAll(Expression<Func<Season, bool>> where = null,
|
||||
Sort<Season> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return await _database.Seasons.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<Season> Create(Season obj)
|
||||
|
||||
public override async Task<Season> Create(Season obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -88,55 +82,15 @@ namespace Kyoo.Controllers
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_database.DiscardChanges();
|
||||
if (Helper.IsDuplicateException(ex))
|
||||
if (IsDuplicateException(ex))
|
||||
throw new DuplicatedItemException($"Trying to insert a duplicated season (slug {obj.Slug} already exists).");
|
||||
throw;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public async Task<Season> CreateIfNotExists(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)
|
||||
protected override async Task Validate(Season obj)
|
||||
{
|
||||
if (obj.ShowID <= 0)
|
||||
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();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Season obj = await Get(showSlug, seasonNumber);
|
||||
await Delete(obj);
|
||||
}
|
||||
|
||||
public async Task Delete(Season obj)
|
||||
public override async Task Delete(Season obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -192,23 +134,5 @@ namespace Kyoo.Controllers
|
||||
if (obj.Episodes != null)
|
||||
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.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.CommonApi;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class ShowRepository : IShowRepository
|
||||
public class ShowRepository : LocalRepository<Show>, IShowRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IStudioRepository _studios;
|
||||
@ -19,6 +18,7 @@ namespace Kyoo.Controllers
|
||||
private readonly IProviderRepository _providers;
|
||||
private readonly ISeasonRepository _seasons;
|
||||
private readonly IEpisodeRepository _episodes;
|
||||
protected override Expression<Func<Show, object>> DefaultSort => x => x.Title;
|
||||
|
||||
public ShowRepository(DatabaseContext database,
|
||||
IStudioRepository studios,
|
||||
@ -27,6 +27,7 @@ namespace Kyoo.Controllers
|
||||
IProviderRepository providers,
|
||||
ISeasonRepository seasons,
|
||||
IEpisodeRepository episodes)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
_studios = studios;
|
||||
@ -36,70 +37,39 @@ namespace Kyoo.Controllers
|
||||
_seasons = seasons;
|
||||
_episodes = episodes;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_database.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());
|
||||
}
|
||||
|
||||
public Task<Show> Get(int id)
|
||||
{
|
||||
return _database.Shows.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
public Task<Show> Get(string slug)
|
||||
{
|
||||
return _database.Shows.FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
await _database.DisposeAsync();
|
||||
await _studios.DisposeAsync();
|
||||
await _people.DisposeAsync();
|
||||
await _genres.DisposeAsync();
|
||||
await _providers.DisposeAsync();
|
||||
await _seasons.DisposeAsync();
|
||||
await _episodes.DisposeAsync();
|
||||
}
|
||||
|
||||
public Task<Show> GetByPath(string path)
|
||||
{
|
||||
return _database.Shows.FirstOrDefaultAsync(x => x.Path == path);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Show>> Search(string query)
|
||||
public override async Task<ICollection<Show>> Search(string query)
|
||||
{
|
||||
return await _database.Shows
|
||||
.FromSqlInterpolated($@"SELECT * FROM Shows WHERE 'Shows.Title' LIKE {$"%{query}%"}
|
||||
OR 'Shows.Aliases' LIKE {$"%{query}%"}")
|
||||
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%")
|
||||
/*|| EF.Functions.ILike(x.Aliases, $"%{query}%")*/)
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Show>> GetAll(Expression<Func<Show, bool>> where = null,
|
||||
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)
|
||||
public override async Task<Show> Create(Show obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -123,7 +93,7 @@ namespace Kyoo.Controllers
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_database.DiscardChanges();
|
||||
if (Helper.IsDuplicateException(ex))
|
||||
if (IsDuplicateException(ex))
|
||||
throw new DuplicatedItemException($"Trying to insert a duplicated show (slug {obj.Slug} already exists).");
|
||||
throw;
|
||||
}
|
||||
@ -131,46 +101,7 @@ namespace Kyoo.Controllers
|
||||
return obj;
|
||||
}
|
||||
|
||||
public async Task<Show> CreateIfNotExists(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)
|
||||
protected override async Task Validate(Show obj)
|
||||
{
|
||||
if (obj.Studio != null)
|
||||
obj.Studio = await _studios.CreateIfNotExists(obj.Studio);
|
||||
@ -210,20 +141,8 @@ namespace Kyoo.Controllers
|
||||
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task Delete(int id)
|
||||
{
|
||||
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)
|
||||
public override async Task Delete(Show obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -258,23 +177,5 @@ namespace Kyoo.Controllers
|
||||
if (obj.Episodes != null)
|
||||
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
|
||||
{
|
||||
public class StudioRepository : IStudioRepository
|
||||
public class StudioRepository : LocalRepository<Studio>, IStudioRepository
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_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)
|
||||
public override async Task<ICollection<Studio>> Search(string query)
|
||||
{
|
||||
return await _database.Studios
|
||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
||||
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Studio>> GetAll(Expression<Func<Studio, bool>> where = null,
|
||||
Sort<Studio> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return await _database.Studios.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<Studio> Create(Studio obj)
|
||||
public override async Task<Studio> Create(Studio obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -68,64 +42,19 @@ namespace Kyoo.Controllers
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_database.DiscardChanges();
|
||||
if (Helper.IsDuplicateException(ex))
|
||||
if (IsDuplicateException(ex))
|
||||
throw new DuplicatedItemException($"Trying to insert a duplicated studio (slug {obj.Slug} already exists).");
|
||||
throw;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public async Task<Studio> CreateIfNotExists(Studio obj)
|
||||
|
||||
protected override Task Validate(Studio ressource)
|
||||
{
|
||||
if (obj == null)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task Delete(Studio obj)
|
||||
public override async Task Delete(Studio obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -137,23 +66,5 @@ namespace Kyoo.Controllers
|
||||
show.StudioID = null;
|
||||
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.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
@ -8,34 +9,39 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class TrackRepository : ITrackRepository
|
||||
public class TrackRepository : LocalRepository<Track>, ITrackRepository
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_database.Dispose();
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
public override Task<Track> Get(string slug)
|
||||
{
|
||||
return _database.DisposeAsync();
|
||||
}
|
||||
|
||||
public async Task<Track> Get(int id)
|
||||
{
|
||||
return await _database.Tracks.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
public Task<Track> Get(string slug)
|
||||
{
|
||||
throw new InvalidOperationException("Tracks do not support the get by slug method.");
|
||||
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}]");
|
||||
}
|
||||
|
||||
string showSlug = match.Groups["show"].Value;
|
||||
int seasonNumber = int.Parse(match.Groups["season"].Value);
|
||||
int episodeNumber = int.Parse(match.Groups["episode"].Value);
|
||||
string language = match.Groups["language"].Value;
|
||||
bool forced = match.Groups["forced"].Success;
|
||||
return _database.Tracks.FirstOrDefaultAsync(x => x.Episode.Show.Slug == showSlug
|
||||
&& x.Episode.SeasonNumber == seasonNumber
|
||||
&& x.Episode.EpisodeNumber == episodeNumber
|
||||
&& x.Language == language
|
||||
&& x.IsForced == forced);
|
||||
}
|
||||
|
||||
public Task<Track> Get(int episodeID, string languageTag, bool isForced)
|
||||
@ -45,19 +51,12 @@ namespace Kyoo.Controllers
|
||||
&& 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.");
|
||||
}
|
||||
|
||||
public async Task<ICollection<Track>> GetAll(Expression<Func<Track, bool>> where = null,
|
||||
Sort<Track> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return await _database.Tracks.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<Track> Create(Track obj)
|
||||
public override async Task<Track> Create(Track obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -74,48 +73,19 @@ namespace Kyoo.Controllers
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
_database.DiscardChanges();
|
||||
if (Helper.IsDuplicateException(ex))
|
||||
if (IsDuplicateException(ex))
|
||||
throw new DuplicatedItemException($"Trying to insert a duplicated track (slug {obj.Slug} already exists).");
|
||||
throw;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public Task<Track> CreateIfNotExists(Track obj)
|
||||
protected override Task Validate(Track ressource)
|
||||
{
|
||||
return Create(obj);
|
||||
}
|
||||
|
||||
public async Task<Track> Edit(Track edited, bool resetOld)
|
||||
{
|
||||
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);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task Delete(Track obj)
|
||||
public override async Task Delete(Track obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
@ -123,23 +93,5 @@ namespace Kyoo.Controllers
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
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