Cleaning up the configuration settings

This commit is contained in:
Zoe Roux 2021-04-23 00:46:38 +02:00
parent 8db47d62fd
commit 540a3c27de
14 changed files with 304 additions and 83 deletions

View File

@ -109,18 +109,18 @@ namespace Kyoo.Models
if (!ep.Show.IsMovie)
{
if (ep.EpisodeNumber > 1)
previous = await library.Get(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber - 1);
previous = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber - 1);
else if (ep.SeasonNumber > 1)
{
int count = await library.GetCount<Episode>(x => x.ShowID == ep.ShowID
&& x.SeasonNumber == ep.SeasonNumber - 1);
previous = await library.Get(ep.ShowID, ep.SeasonNumber - 1, count);
previous = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber - 1, count);
}
if (ep.EpisodeNumber >= await library.GetCount<Episode>(x => x.SeasonID == ep.SeasonID))
next = await library.Get(ep.ShowID, ep.SeasonNumber + 1, 1);
next = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber + 1, 1);
else
next = await library.Get(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber + 1);
next = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber + 1);
}
return new WatchItem(ep.ID,

View File

@ -86,7 +86,7 @@ namespace Kyoo.Controllers
/// <inheritdoc />
public override async Task<Episode> GetOrDefault(int id)
{
Episode ret = await base.Get(id);
Episode ret = await base.GetOrDefault(id);
if (ret != null)
ret.ShowSlug = await _shows.GetSlug(ret.ShowID);
return ret;
@ -111,9 +111,9 @@ namespace Kyoo.Controllers
}
/// <inheritdoc />
public override async Task<Episode> GetOrDefault(Expression<Func<Episode, bool>> predicate)
public override async Task<Episode> GetOrDefault(Expression<Func<Episode, bool>> where)
{
Episode ret = await base.Get(predicate);
Episode ret = await base.GetOrDefault(where);
if (ret != null)
ret.ShowSlug = await _shows.GetSlug(ret.ShowID);
return ret;

View File

@ -92,15 +92,15 @@ namespace Kyoo.Controllers
}
/// <inheritdoc />
public override async Task<LibraryItem> Get(int id)
public override async Task<LibraryItem> GetOrDefault(int id)
{
return id > 0
? new LibraryItem(await _shows.Value.Get(id))
: new LibraryItem(await _collections.Value.Get(-id));
? new LibraryItem(await _shows.Value.GetOrDefault(id))
: new LibraryItem(await _collections.Value.GetOrDefault(-id));
}
/// <inheritdoc />
public override Task<LibraryItem> Get(string slug)
public override Task<LibraryItem> GetOrDefault(string slug)
{
throw new InvalidOperationException("You can't get a library item by a slug.");
}
@ -189,7 +189,7 @@ namespace Kyoo.Controllers
where,
sort,
limit);
if (!items.Any() && await _libraries.Value.Get(id) == null)
if (!items.Any() && await _libraries.Value.GetOrDefault(id) == null)
throw new ItemNotFound();
return items;
}
@ -204,7 +204,7 @@ namespace Kyoo.Controllers
where,
sort,
limit);
if (!items.Any() && await _libraries.Value.Get(slug) == null)
if (!items.Any() && await _libraries.Value.GetOrDefault(slug) == null)
throw new ItemNotFound();
return items;
}

View File

@ -98,9 +98,9 @@ namespace Kyoo.Controllers
}
/// <inheritdoc/>
public override async Task<Season> Get(Expression<Func<Season, bool>> predicate)
public override async Task<Season> Get(Expression<Func<Season, bool>> where)
{
Season ret = await base.Get(predicate);
Season ret = await base.Get(where);
ret.ShowSlug = await _shows.GetSlug(ret.ShowID);
return ret;
}

View File

@ -36,13 +36,13 @@ namespace Kyoo.Controllers
/// <inheritdoc />
public override Task<Track> Get(string slug)
Task<Track> IRepository<Track>.Get(string slug)
{
return Get(slug, StreamType.Unknown);
return Get(slug);
}
/// <inheritdoc />
public async Task<Track> Get(string slug, StreamType type)
public async Task<Track> Get(string slug, StreamType type = StreamType.Unknown)
{
Track ret = await GetOrDefault(slug, type);
if (ret == null)
@ -51,7 +51,7 @@ namespace Kyoo.Controllers
}
/// <inheritdoc />
public Task<Track> GetOrDefault(string slug, StreamType type)
public Task<Track> GetOrDefault(string slug, StreamType type = StreamType.Unknown)
{
Match match = Regex.Match(slug,
@"(?<show>.*)-s(?<season>\d+)e(?<episode>\d+)(\.(?<type>\w*))?\.(?<language>.{0,3})(?<forced>-forced)?(\..*)?");

View File

@ -113,10 +113,8 @@
</Target>
<Target Name="BuildTranscoder" BeforeTargets="BeforeBuild" Condition="'$(SkipTranscoder)' != 'true'">
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' != 'true'"
Command="mkdir -p build %26%26 cd build %26%26 cmake .. %26%26 make -j" />
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' == 'true'"
Command='(if not exist build mkdir build) %26%26 cd build %26%26 cmake .. -G "NMake Makefiles" %26%26 nmake' />
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' != 'true'" Command="mkdir -p build %26%26 cd build %26%26 cmake .. %26%26 make -j" />
<Exec WorkingDirectory="$(TranscoderRoot)" Condition="'$(IsWindows)' == 'true'" Command="(if not exist build mkdir build) %26%26 cd build %26%26 cmake .. -G &quot;NMake Makefiles&quot; %26%26 nmake" />
<Copy SourceFiles="$(TranscoderRoot)/build/$(TranscoderBinary)" DestinationFolder="." />
</Target>

View File

@ -2,6 +2,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Kyoo.Controllers;
using Kyoo.Models;
using Kyoo.Models.Exceptions;
using Microsoft.EntityFrameworkCore;
@ -10,28 +11,71 @@ using Npgsql;
namespace Kyoo
{
/// <summary>
/// The database handle used for all local repositories.
/// </summary>
/// <remarks>
/// It should not be used directly, to access the database use a <see cref="ILibraryManager"/> or repositories.
/// </remarks>
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
{
ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
ChangeTracker.LazyLoadingEnabled = false;
}
/// <summary>
/// All libraries of Kyoo. See <see cref="Library"/>.
/// </summary>
public DbSet<Library> Libraries { get; set; }
/// <summary>
/// All collections of Kyoo. See <see cref="Collection"/>.
/// </summary>
public DbSet<Collection> Collections { get; set; }
/// <summary>
/// All shows of Kyoo. See <see cref="Show"/>.
/// </summary>
public DbSet<Show> Shows { get; set; }
/// <summary>
/// All seasons of Kyoo. See <see cref="Season"/>.
/// </summary>
public DbSet<Season> Seasons { get; set; }
/// <summary>
/// All episodes of Kyoo. See <see cref="Episode"/>.
/// </summary>
public DbSet<Episode> Episodes { get; set; }
/// <summary>
/// All tracks of Kyoo. See <see cref="Track"/>.
/// </summary>
public DbSet<Track> Tracks { get; set; }
/// <summary>
/// All genres of Kyoo. See <see cref="Genres"/>.
/// </summary>
public DbSet<Genre> Genres { get; set; }
/// <summary>
/// All people of Kyoo. See <see cref="People"/>.
/// </summary>
public DbSet<People> People { get; set; }
/// <summary>
/// All studios of Kyoo. See <see cref="Studio"/>.
/// </summary>
public DbSet<Studio> Studios { get; set; }
/// <summary>
/// All providers of Kyoo. See <see cref="Provider"/>.
/// </summary>
public DbSet<Provider> Providers { get; set; }
/// <summary>
/// All metadataIDs (ExternalIDs) of Kyoo. See <see cref="MetadataID"/>.
/// </summary>
public DbSet<MetadataID> MetadataIds { get; set; }
/// <summary>
/// All people's role. See <see cref="PeopleRole"/>.
/// </summary>
public DbSet<PeopleRole> PeopleRoles { get; set; }
/// <summary>
/// Get a generic link between two resource types.
/// </summary>
/// <remarks>Types are order dependant. You can't inverse the order. Please always put the owner first.</remarks>
/// <typeparam name="T1">The first resource type of the relation. It is the owner of the second</typeparam>
/// <typeparam name="T2">The second resource type of the relation. It is the contained resource.</typeparam>
/// <returns>All links between the two types.</returns>
public DbSet<Link<T1, T2>> Links<T1, T2>()
where T1 : class, IResource
where T2 : class, IResource
@ -40,6 +84,9 @@ namespace Kyoo
}
/// <summary>
/// A basic constructor that set default values (query tracker behaviors, mapping enums...)
/// </summary>
public DatabaseContext()
{
NpgsqlConnection.GlobalTypeMapper.MapEnum<Status>();
@ -50,6 +97,21 @@ namespace Kyoo
ChangeTracker.LazyLoadingEnabled = false;
}
/// <summary>
/// Create a new <see cref="DatabaseContext"/>.
/// </summary>
/// <param name="options">Connection options to use (witch databse provider to use, connection strings...)</param>
public DatabaseContext(DbContextOptions<DatabaseContext> options)
: base(options)
{
ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
ChangeTracker.LazyLoadingEnabled = false;
}
/// <summary>
/// Set database parameters to support every types of Kyoo.
/// </summary>
/// <param name="modelBuilder">The database's model builder.</param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
@ -58,14 +120,6 @@ namespace Kyoo
modelBuilder.HasPostgresEnum<ItemType>();
modelBuilder.HasPostgresEnum<StreamType>();
// modelBuilder.Entity<Library>()
// .Property(x => x.Paths)
// .HasColumnType("text[]");
//
// modelBuilder.Entity<Show>()
// .Property(x => x.Aliases)
// .HasColumnType("text[]");
modelBuilder.Entity<Track>()
.Property(t => t.IsDefault)
.ValueGeneratedNever();
@ -196,6 +250,13 @@ namespace Kyoo
.IsUnique();
}
/// <summary>
/// Return a new or an in cache temporary object wih the same ID as the one given
/// </summary>
/// <param name="model">If a resource with the same ID is found in the database, it will be used.
/// <see cref="model"/> will be used overwise</param>
/// <typeparam name="T">The type of the resource</typeparam>
/// <returns>A resource that is now tracked by this context.</returns>
public T GetTemporaryObject<T>(T model)
where T : class, IResource
{
@ -206,6 +267,11 @@ namespace Kyoo
return model;
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public override int SaveChanges()
{
try
@ -221,6 +287,13 @@ namespace Kyoo
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="acceptAllChangesOnSuccess">Indicates whether AcceptAllChanges() is called after the changes
/// have been sent successfully to the database.</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
try
@ -236,6 +309,13 @@ namespace Kyoo
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="duplicateMessage">The message that will have the <see cref="DuplicatedItemException"/>
/// (if a duplicate is found).</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public int SaveChanges(string duplicateMessage)
{
try
@ -251,6 +331,14 @@ namespace Kyoo
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="acceptAllChangesOnSuccess">Indicates whether AcceptAllChanges() is called after the changes
/// have been sent successfully to the database.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess,
CancellationToken cancellationToken = new())
{
@ -267,6 +355,12 @@ namespace Kyoo
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new())
{
try
@ -282,6 +376,14 @@ namespace Kyoo
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="duplicateMessage">The message that will have the <see cref="DuplicatedItemException"/>
/// (if a duplicate is found).</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public async Task<int> SaveChangesAsync(string duplicateMessage,
CancellationToken cancellationToken = new())
{
@ -298,6 +400,12 @@ namespace Kyoo
}
}
/// <summary>
/// Save changes if no duplicates are found. If one is found, no change are saved but the current changes are no discarded.
/// The current context will still hold those invalid changes.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <returns>The number of state entries written to the database or -1 if a duplicate exist.</returns>
public async Task<int> SaveIfNoDuplicates(CancellationToken cancellationToken = new())
{
try
@ -310,12 +418,31 @@ namespace Kyoo
}
}
/// <summary>
/// Save items or retry with a custom method if a duplicate is found.
/// </summary>
/// <param name="obj">The item to save (other changes of this context will also be saved)</param>
/// <param name="onFail">A function to run on fail, the <see cref="obj"/> param wil be mapped.
/// The second parameter is the current retry number.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <typeparam name="T">The type of the item to save</typeparam>
/// <returns>The number of state entries written to the database.</returns>
public Task<T> SaveOrRetry<T>(T obj, Func<T, int, T> onFail, CancellationToken cancellationToken = new())
{
return SaveOrRetry(obj, onFail, 0, cancellationToken);
}
public async Task<T> SaveOrRetry<T>(T obj,
/// <summary>
/// Save items or retry with a custom method if a duplicate is found.
/// </summary>
/// <param name="obj">The item to save (other changes of this context will also be saved)</param>
/// <param name="onFail">A function to run on fail, the <see cref="obj"/> param wil be mapped.
/// The second parameter is the current retry number.</param>
/// <param name="recurse">The current retry number.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <typeparam name="T">The type of the item to save</typeparam>
/// <returns>The number of state entries written to the database.</returns>
private async Task<T> SaveOrRetry<T>(T obj,
Func<T, int, T> onFail,
int recurse,
CancellationToken cancellationToken = new())
@ -337,11 +464,20 @@ namespace Kyoo
}
}
/// <summary>
/// Check if the exception is a duplicated exception.
/// </summary>
/// <remarks>WARNING: this only works for PostgreSQL</remarks>
/// <param name="ex">The exception to check</param>
/// <returns>True if the exception is a duplicate exception. False otherwise</returns>
private static bool IsDuplicateException(Exception ex)
{
return ex.InnerException is PostgresException {SqlState: PostgresErrorCodes.UniqueViolation};
}
/// <summary>
/// Delete every changes that are on this context.
/// </summary>
private void DiscardChanges()
{
foreach (EntityEntry entry in ChangeTracker.Entries().Where(x => x.State != EntityState.Unchanged

View File

@ -3,7 +3,11 @@ using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.VisualBasic.FileIO;
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Kyoo
{
@ -18,11 +22,8 @@ namespace Kyoo
/// <param name="args">Command line arguments</param>
public static async Task Main(string[] args)
{
if (args.Length > 0)
FileSystem.CurrentDirectory = args[0];
if (!File.Exists("./appsettings.json"))
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json"), "appsettings.json");
if (!File.Exists("./settings.json"))
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "settings.json"), "settings.json");
bool? debug = Environment.GetEnvironmentVariable("ENVIRONMENT")?.ToLowerInvariant() switch
{
@ -49,15 +50,50 @@ namespace Kyoo
await host.Build().RunAsync();
}
/// <summary>
/// Register settings.json, environment variables and command lines arguments as configuration.
/// </summary>
/// <param name="builder">The configuration builder to use</param>
/// <param name="args">The command line arguments</param>
/// <returns>The modified configuration builder</returns>
private static IConfigurationBuilder SetupConfig(IConfigurationBuilder builder, string[] args)
{
return builder.AddJsonFile("./settings.json", false, true)
.AddEnvironmentVariables()
.AddCommandLine(args);
}
/// <summary>
/// Createa a web host
/// </summary>
/// <param name="args">Command line parameters that can be handled by kestrel</param>
/// <returns>A new web host instance</returns>
private static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseKestrel(config => { config.AddServerHeader = false; })
.UseUrls("http://*:5000")
private static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
WebHost.CreateDefaultBuilder(args);
return new WebHostBuilder()
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
.UseConfiguration(SetupConfig(new ConfigurationBuilder(), args).Build())
.ConfigureAppConfiguration(x => SetupConfig(x, args))
.ConfigureLogging((context, builder) =>
{
builder.AddConfiguration(context.Configuration.GetSection("logging"))
.AddConsole()
.AddDebug()
.AddEventSourceLogger();
})
.UseDefaultServiceProvider((context, options) =>
{
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
if (context.HostingEnvironment.IsDevelopment())
StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
})
.ConfigureServices(x => x.AddRouting())
.UseKestrel(options => { options.AddServerHeader = false; })
.UseIIS()
.UseIISIntegration()
.UseStartup<Startup>();
}
}
}

View File

@ -64,14 +64,28 @@ namespace Kyoo.Api
[Authorize(Policy = "Read")]
public async Task<ActionResult<Season>> GetSeason(string showSlug, int seasonNumber, int episodeNumber)
{
return await _libraryManager.Get(showSlug, seasonNumber);
try
{
return await _libraryManager.Get(showSlug, seasonNumber);
}
catch (ItemNotFound)
{
return NotFound();
}
}
[HttpGet("{showID:int}-{seasonNumber:int}e{episodeNumber:int}/season")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Season>> GetSeason(int showID, int seasonNumber, int episodeNumber)
{
return await _libraryManager.Get(showID, seasonNumber);
try
{
return await _libraryManager.Get(showID, seasonNumber);
}
catch (ItemNotFound)
{
return NotFound();
}
}
[HttpGet("{episodeID:int}/track")]
@ -120,7 +134,7 @@ namespace Kyoo.Api
new Sort<Track>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.Get(showID, seasonNumber, episodeNumber) == null)
if (!resources.Any() && await _libraryManager.GetOrDefault(showID, seasonNumber, episodeNumber) == null)
return NotFound();
return Page(resources, limit);
}
@ -130,10 +144,10 @@ namespace Kyoo.Api
}
}
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/track")]
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/tracks")]
[HttpGet("{slug}-s{seasonNumber:int}e{episodeNumber:int}/track")]
[HttpGet("{slug}-s{seasonNumber:int}e{episodeNumber:int}/tracks")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Page<Track>>> GetEpisode(string showSlug,
public async Task<ActionResult<Page<Track>>> GetEpisode(string slug,
int seasonNumber,
int episodeNumber,
[FromQuery] string sortBy,
@ -144,13 +158,13 @@ namespace Kyoo.Api
try
{
ICollection<Track> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Track>(where, x => x.Episode.Show.Slug == showSlug
ApiHelper.ParseWhere<Track>(where, x => x.Episode.Show.Slug == slug
&& x.Episode.SeasonNumber == seasonNumber
&& x.Episode.EpisodeNumber == episodeNumber),
new Sort<Track>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.Get(showSlug, seasonNumber, episodeNumber) == null)
if (!resources.Any() && await _libraryManager.GetOrDefault(slug, seasonNumber, episodeNumber) == null)
return NotFound();
return Page(resources, limit);
}

View File

@ -75,7 +75,7 @@ namespace Kyoo.Api
new Sort<Episode>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.Get(showSlug, seasonNumber) == null)
if (!resources.Any() && await _libraryManager.GetOrDefault(showSlug, seasonNumber) == null)
return NotFound();
return Page(resources, limit);
}
@ -102,7 +102,7 @@ namespace Kyoo.Api
new Sort<Episode>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.Get(showID, seasonNumber) == null)
if (!resources.Any() && await _libraryManager.GetOrDefault(showID, seasonNumber) == null)
return NotFound();
return Page(resources, limit);
}

View File

@ -30,14 +30,14 @@ namespace Kyoo.Api
Track subtitle;
try
{
subtitle = await _libraryManager.Get(slug, StreamType.Subtitle);
subtitle = await _libraryManager.GetOrDefault(slug, StreamType.Subtitle);
}
catch (ArgumentException ex)
{
return BadRequest(new {error = ex.Message});
}
if (subtitle == null || subtitle.Type != StreamType.Subtitle)
if (subtitle is not {Type: StreamType.Subtitle})
return NotFound();
if (subtitle.Codec == "subrip" && extension == "vtt")

View File

@ -1,31 +1,25 @@
{
"server.urls": "http://0.0.0.0:5000",
"server.urls": "http://*:5000",
"public_url": "http://localhost:5000/",
"http_port": 5000,
"https_port": 44300,
"Database": {
"Server": "127.0.0.1",
"Port": "5432",
"Database": "kyooDB",
"User Id": "kyoo",
"Password": "kyooPassword",
"Pooling": "true",
"MaxPoolSize": "95",
"Timeout": "30"
"database": {
"server": "127.0.0.1",
"port": "5432",
"database": "kyooDB",
"user ID": "kyoo",
"password": "kyooPassword",
"pooling": "true",
"maxPoolSize": "95",
"timeout": "30"
},
"Logging": {
"LogLevel": {
"Default": "Warning",
"logging": {
"logLevel": {
"default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore.DbUpdateException": "None",
"Microsoft.EntityFrameworkCore.Update": "None",
"Microsoft.EntityFrameworkCore.Database.Command": "None"
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"parallelTasks": "1",

View File

@ -5,7 +5,8 @@ After=network.target
[Service]
User=kyoo
ExecStart=/usr/lib/kyoo/Kyoo /var/lib/kyoo
WorkingDirectory=/var/lib/kyoo
ExecStart=/usr/lib/kyoo/Kyoo
Restart=on-abort
TimeoutSec=20

42
settings.json Normal file
View File

@ -0,0 +1,42 @@
{
"server.urls": "http://*:5000",
"public_url": "http://localhost:5000/",
"database": {
"server": "127.0.0.1",
"port": "5432",
"database": "kyooDB",
"user ID": "kyoo",
"password": "kyooPassword",
"pooling": "true",
"maxPoolSize": "95",
"timeout": "30"
},
"logging": {
"logLevel": {
"default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"parallelTasks": "1",
"scheduledTasks": {
"scan": "24:00:00"
},
"certificatePassword": "passphrase",
"transmuxTempPath": "cached/kyoo/transmux",
"transcodeTempPath": "cached/kyoo/transcode",
"peoplePath": "people",
"providerPath": "providers",
"profilePicturePath": "users/",
"plugins": "plugins/",
"defaultPermissions": "read,play,write,admin",
"newUserPermissions": "read,play,write,admin",
"regex": "(?:\\/(?<Collection>.*?))?\\/(?<Show>.*?)(?: \\(\\d+\\))?\\/\\k<Show>(?: \\(\\d+\\))?(?:(?: S(?<Season>\\d+)E(?<Episode>\\d+))| (?<Absolute>\\d+))?.*$",
"subtitleRegex": "^(?<Episode>.*)\\.(?<Language>\\w{1,3})\\.(?<Default>default\\.)?(?<Forced>forced\\.)?.*$"
}