mirror of
https://github.com/sphildreth/roadie
synced 2024-11-10 06:44:12 +00:00
Removed Image table definition, resolves #34
This commit is contained in:
parent
82544c143b
commit
818afd2eb0
25 changed files with 380 additions and 567 deletions
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.4.4" />
|
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.4.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.1" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace Roadie.Library.Configuration
|
||||||
{
|
{
|
||||||
public enum DbContexts : short
|
public enum DbContexts : short
|
||||||
{
|
{
|
||||||
MySQL = 1
|
MySQL = 1,
|
||||||
|
File = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
Roadie.Api.Library/Configuration/FileDatabaseFormat.cs
Normal file
14
Roadie.Api.Library/Configuration/FileDatabaseFormat.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Roadie.Library.Configuration
|
||||||
|
{
|
||||||
|
public enum FileDatabaseFormat
|
||||||
|
{
|
||||||
|
JSON,
|
||||||
|
BSON,
|
||||||
|
XML,
|
||||||
|
CSV
|
||||||
|
}
|
||||||
|
}
|
25
Roadie.Api.Library/Configuration/FileDatabaseOptions.cs
Normal file
25
Roadie.Api.Library/Configuration/FileDatabaseOptions.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Roadie.Library.Configuration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Options specific when using a FileDatabase DbContext.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FileDatabaseOptions : IFileDatabaseOptions
|
||||||
|
{
|
||||||
|
public FileDatabaseFormat DatabaseFormat { get; set; }
|
||||||
|
|
||||||
|
public string DatabaseName { get; set; }
|
||||||
|
|
||||||
|
public string DatabaseFolder { get; set; }
|
||||||
|
|
||||||
|
public FileDatabaseOptions()
|
||||||
|
{
|
||||||
|
DatabaseFormat = FileDatabaseFormat.BSON;
|
||||||
|
DatabaseName = "roadie";
|
||||||
|
DatabaseFolder = @"M:\db";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Roadie.Api.Library/Configuration/IFileDatabaseOptions.cs
Normal file
8
Roadie.Api.Library/Configuration/IFileDatabaseOptions.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Roadie.Library.Configuration
|
||||||
|
{
|
||||||
|
public interface IFileDatabaseOptions
|
||||||
|
{
|
||||||
|
string DatabaseFolder { get; set; }
|
||||||
|
FileDatabaseFormat DatabaseFormat { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ namespace Roadie.Library.Configuration
|
||||||
string ConnectionString { get; set; }
|
string ConnectionString { get; set; }
|
||||||
string ContentPath { get; set; }
|
string ContentPath { get; set; }
|
||||||
Converting Converting { get; set; }
|
Converting Converting { get; set; }
|
||||||
|
FileDatabaseOptions FileDatabaseOptions { get; set; }
|
||||||
short DefaultRowsPerPage { get; set; }
|
short DefaultRowsPerPage { get; set; }
|
||||||
string DefaultTimeZone { get; set; }
|
string DefaultTimeZone { get; set; }
|
||||||
Dlna Dlna { get; set; }
|
Dlna Dlna { get; set; }
|
||||||
|
|
|
@ -37,6 +37,8 @@ namespace Roadie.Library.Configuration
|
||||||
|
|
||||||
public Converting Converting { get; set; }
|
public Converting Converting { get; set; }
|
||||||
|
|
||||||
|
public FileDatabaseOptions FileDatabaseOptions { get; set; }
|
||||||
|
|
||||||
public short DefaultRowsPerPage { get; set; }
|
public short DefaultRowsPerPage { get; set; }
|
||||||
public string DefaultTimeZone { get; set; }
|
public string DefaultTimeZone { get; set; }
|
||||||
|
|
||||||
|
@ -175,6 +177,7 @@ namespace Roadie.Library.Configuration
|
||||||
|
|
||||||
Inspector = new Inspector();
|
Inspector = new Inspector();
|
||||||
Converting = new Converting();
|
Converting = new Converting();
|
||||||
|
FileDatabaseOptions = new FileDatabaseOptions();
|
||||||
Integrations = new Integrations();
|
Integrations = new Integrations();
|
||||||
Processing = new Processing();
|
Processing = new Processing();
|
||||||
Dlna = new Dlna();
|
Dlna = new Dlna();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
using FileContextCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
|
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
|
||||||
using Roadie.Library.Configuration;
|
using Roadie.Library.Configuration;
|
||||||
using Roadie.Library.Data.Context.Implementation;
|
using Roadie.Library.Data.Context.Implementation;
|
||||||
|
@ -12,6 +13,13 @@ namespace Roadie.Library.Data.Context
|
||||||
{
|
{
|
||||||
switch (configuration.DbContextToUse)
|
switch (configuration.DbContextToUse)
|
||||||
{
|
{
|
||||||
|
case DbContexts.File:
|
||||||
|
var fileOptionsBuilder = new DbContextOptionsBuilder<MySQLRoadieDbContext>();
|
||||||
|
fileOptionsBuilder.UseFileContextDatabase(configuration.FileDatabaseOptions.DatabaseFormat.ToString().ToLower(),
|
||||||
|
databaseName: configuration.FileDatabaseOptions.DatabaseName,
|
||||||
|
location: configuration.FileDatabaseOptions.DatabaseFolder);
|
||||||
|
return new FileRoadieDbContext(fileOptionsBuilder.Options);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var mysqlOptionsBuilder = new DbContextOptionsBuilder<MySQLRoadieDbContext>();
|
var mysqlOptionsBuilder = new DbContextOptionsBuilder<MySQLRoadieDbContext>();
|
||||||
mysqlOptionsBuilder.UseMySql(configuration.ConnectionString, mySqlOptions =>
|
mysqlOptionsBuilder.UseMySql(configuration.ConnectionString, mySqlOptions =>
|
||||||
|
|
|
@ -26,7 +26,6 @@ namespace Roadie.Library.Data.Context
|
||||||
DbSet<Comment> Comments { get; set; }
|
DbSet<Comment> Comments { get; set; }
|
||||||
DatabaseFacade Database { get; }
|
DatabaseFacade Database { get; }
|
||||||
DbSet<Genre> Genres { get; set; }
|
DbSet<Genre> Genres { get; set; }
|
||||||
DbSet<Image> Images { get; set; }
|
|
||||||
DbSet<Label> Labels { get; set; }
|
DbSet<Label> Labels { get; set; }
|
||||||
DbSet<Playlist> Playlists { get; set; }
|
DbSet<Playlist> Playlists { get; set; }
|
||||||
DbSet<PlaylistTrack> PlaylistTracks { get; set; }
|
DbSet<PlaylistTrack> PlaylistTracks { get; set; }
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Roadie.Library.Data.Context.Implementation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// File based Context using FileContextCore
|
||||||
|
/// <seealso cref="https://github.com/morrisjdev/FileContextCore"/>
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FileRoadieDbContext : LinqDbContextBase
|
||||||
|
{
|
||||||
|
public FileRoadieDbContext(DbContextOptions options)
|
||||||
|
: base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Roadie.Library.Data.Context.Implementation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base DbContext using just LINQ statements against EF
|
||||||
|
/// </summary>
|
||||||
|
public abstract class LinqDbContextBase : RoadieDbContext
|
||||||
|
{
|
||||||
|
public LinqDbContextBase(DbContextOptions options)
|
||||||
|
: base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Artist> LastPlayedArtist(int userId)
|
||||||
|
{
|
||||||
|
return await (from ut in UserTracks
|
||||||
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
|
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
|
join r in Releases on rm.ReleaseId equals r.Id
|
||||||
|
join a in Artists on r.ArtistId equals a.Id
|
||||||
|
where ut.UserId == userId
|
||||||
|
orderby ut.LastPlayed descending
|
||||||
|
select a).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Release> LastPlayedRelease(int userId)
|
||||||
|
{
|
||||||
|
return await (from ut in UserTracks
|
||||||
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
|
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
|
join r in Releases on rm.ReleaseId equals r.Id
|
||||||
|
where ut.UserId == userId
|
||||||
|
orderby ut.LastPlayed descending
|
||||||
|
select r).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Track> LastPlayedTrack(int userId)
|
||||||
|
{
|
||||||
|
return await (from ut in UserTracks
|
||||||
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
|
where ut.UserId == userId
|
||||||
|
orderby ut.LastPlayed descending
|
||||||
|
select t).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Artist> MostPlayedArtist(int userId)
|
||||||
|
{
|
||||||
|
var mostPlayedTrack = await MostPlayedTrack(userId);
|
||||||
|
if (mostPlayedTrack != null)
|
||||||
|
{
|
||||||
|
return await (from t in Tracks
|
||||||
|
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
|
join r in Releases on rm.ReleaseId equals r.Id
|
||||||
|
join a in Artists on r.ArtistId equals a.Id
|
||||||
|
where t.Id == mostPlayedTrack.Id
|
||||||
|
select a).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Release> MostPlayedRelease(int userId)
|
||||||
|
{
|
||||||
|
var mostPlayedTrack = await MostPlayedTrack(userId);
|
||||||
|
if (mostPlayedTrack != null)
|
||||||
|
{
|
||||||
|
return await (from t in Tracks
|
||||||
|
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
|
join r in Releases on rm.ReleaseId equals r.Id
|
||||||
|
where t.Id == mostPlayedTrack.Id
|
||||||
|
select r).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Track> MostPlayedTrack(int userId)
|
||||||
|
{
|
||||||
|
return await (from ut in UserTracks
|
||||||
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
|
where ut.UserId == userId
|
||||||
|
orderby ut.PlayedCount descending
|
||||||
|
select t).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||||
|
{
|
||||||
|
List<Artist> randomArtists = null;
|
||||||
|
if (doOnlyFavorites)
|
||||||
|
{
|
||||||
|
randomArtists = await (from ua in UserArtists
|
||||||
|
join a in Artists on ua.ArtistId equals a.Id
|
||||||
|
where ua.UserId == userId
|
||||||
|
where ua.IsFavorite == true
|
||||||
|
select a
|
||||||
|
).OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
else if (doOnlyRated)
|
||||||
|
{
|
||||||
|
randomArtists = await (from ua in UserArtists
|
||||||
|
join a in Artists on ua.ArtistId equals a.Id
|
||||||
|
where ua.UserId == userId
|
||||||
|
where ua.Rating > 0
|
||||||
|
select a
|
||||||
|
).OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
randomArtists = await Artists.OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
var dict = randomArtists.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||||
|
return new SortedDictionary<int, int>(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||||
|
{
|
||||||
|
var randomGenres = await Genres.OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
var dict = randomGenres.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||||
|
return new SortedDictionary<int, int>(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||||
|
{
|
||||||
|
var randomLabels = await Labels.OrderBy(x => Guid.NewGuid()).Take(randomLimit).ToListAsync();
|
||||||
|
var dict = randomLabels.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||||
|
return new SortedDictionary<int, int>(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||||
|
{
|
||||||
|
List<Release> randomReleases = null;
|
||||||
|
if (doOnlyFavorites)
|
||||||
|
{
|
||||||
|
randomReleases = await (from ur in UserReleases
|
||||||
|
join r in Releases on ur.ReleaseId equals r.Id
|
||||||
|
where ur.UserId == userId
|
||||||
|
where ur.IsFavorite == true
|
||||||
|
select r
|
||||||
|
).OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
else if (doOnlyRated)
|
||||||
|
{
|
||||||
|
randomReleases = await (from ur in UserReleases
|
||||||
|
join r in Releases on ur.ReleaseId equals r.Id
|
||||||
|
where ur.UserId == userId
|
||||||
|
where ur.Rating > 0
|
||||||
|
select r
|
||||||
|
).OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
randomReleases = await Releases.OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
var dict = randomReleases.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||||
|
return new SortedDictionary<int, int>(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||||
|
{
|
||||||
|
List<Track> randomTracks = null;
|
||||||
|
if (doOnlyFavorites)
|
||||||
|
{
|
||||||
|
randomTracks = await (from ut in UserTracks
|
||||||
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
|
where ut.UserId == userId
|
||||||
|
where ut.IsFavorite == true
|
||||||
|
select t
|
||||||
|
).OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
else if (doOnlyRated)
|
||||||
|
{
|
||||||
|
randomTracks = await (from ut in UserTracks
|
||||||
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
|
where ut.UserId == userId
|
||||||
|
where ut.Rating > 0
|
||||||
|
select t
|
||||||
|
).OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
randomTracks = await Tracks.OrderBy(x => Guid.NewGuid())
|
||||||
|
.Take(randomLimit)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
var dict = randomTracks.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||||
|
return new SortedDictionary<int, int>(dict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -7,7 +6,7 @@ using System.Threading.Tasks;
|
||||||
namespace Roadie.Library.Data.Context.Implementation
|
namespace Roadie.Library.Data.Context.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MySQL/MariaDB implementation of DbContext
|
/// MySQL/MariaDB implementation of DbContext using SQL statements for better performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MySQLRoadieDbContext : RoadieDbContext
|
public sealed class MySQLRoadieDbContext : RoadieDbContext
|
||||||
{
|
{
|
||||||
|
@ -37,7 +36,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
join `track` t on (ut.trackId = t.id)
|
join `track` t on (ut.trackId = t.id)
|
||||||
join `releasemedia` rm on (t.releaseMediaId = rm.id)
|
join `releasemedia` rm on (t.releaseMediaId = rm.id)
|
||||||
join `release` r on (rm.releaseId = r.id)
|
join `release` r on (rm.releaseId = r.id)
|
||||||
WHERE ut.userId = {0}
|
WHERE ut.userId = {0}
|
||||||
ORDER by ut.lastPlayed desc
|
ORDER by ut.lastPlayed desc
|
||||||
LIMIT 1";
|
LIMIT 1";
|
||||||
return await Releases.FromSqlRaw(sql, userId)
|
return await Releases.FromSqlRaw(sql, userId)
|
||||||
|
|
|
@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
using Roadie.Library.Enums;
|
using Roadie.Library.Enums;
|
||||||
using Roadie.Library.Identity;
|
using Roadie.Library.Identity;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -35,8 +34,6 @@ namespace Roadie.Library.Data.Context
|
||||||
|
|
||||||
public DbSet<Genre> Genres { get; set; }
|
public DbSet<Genre> Genres { get; set; }
|
||||||
|
|
||||||
public DbSet<Image> Images { get; set; }
|
|
||||||
|
|
||||||
public DbSet<Label> Labels { get; set; }
|
public DbSet<Label> Labels { get; set; }
|
||||||
|
|
||||||
public DbSet<Playlist> Playlists { get; set; }
|
public DbSet<Playlist> Playlists { get; set; }
|
||||||
|
@ -72,7 +69,7 @@ namespace Roadie.Library.Data.Context
|
||||||
public DbSet<UserTrack> UserTracks { get; set; }
|
public DbSet<UserTrack> UserTracks { get; set; }
|
||||||
public DbSet<InviteToken> InviteTokens { get; set; }
|
public DbSet<InviteToken> InviteTokens { get; set; }
|
||||||
|
|
||||||
public RoadieDbContext(DbContextOptions options)
|
public RoadieDbContext(DbContextOptions options)
|
||||||
: base(options)
|
: base(options)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -218,10 +215,15 @@ namespace Roadie.Library.Data.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
Task<EntityEntry> IRoadieDbContext.AddAsync(object entity, CancellationToken cancellationToken) => throw new NotImplementedException();
|
Task<EntityEntry> IRoadieDbContext.AddAsync(object entity, CancellationToken cancellationToken) => throw new NotImplementedException();
|
||||||
|
|
||||||
Task<EntityEntry<TEntity>> IRoadieDbContext.AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken) => throw new NotImplementedException();
|
Task<EntityEntry<TEntity>> IRoadieDbContext.AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken) => throw new NotImplementedException();
|
||||||
|
|
||||||
Task<TEntity> IRoadieDbContext.FindAsync<TEntity>(params object[] keyValues) => throw new NotImplementedException();
|
Task<TEntity> IRoadieDbContext.FindAsync<TEntity>(params object[] keyValues) => throw new NotImplementedException();
|
||||||
|
|
||||||
Task<object> IRoadieDbContext.FindAsync(Type entityType, object[] keyValues, CancellationToken cancellationToken) => throw new NotImplementedException();
|
Task<object> IRoadieDbContext.FindAsync(Type entityType, object[] keyValues, CancellationToken cancellationToken) => throw new NotImplementedException();
|
||||||
|
|
||||||
Task<TEntity> IRoadieDbContext.FindAsync<TEntity>(object[] keyValues, CancellationToken cancellationToken) => throw new NotImplementedException();
|
Task<TEntity> IRoadieDbContext.FindAsync<TEntity>(object[] keyValues, CancellationToken cancellationToken) => throw new NotImplementedException();
|
||||||
|
|
||||||
Task<object> IRoadieDbContext.FindAsync(Type entityType, params object[] keyValues) => throw new NotImplementedException();
|
Task<object> IRoadieDbContext.FindAsync(Type entityType, params object[] keyValues) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace Roadie.Library.Data
|
|
||||||
{
|
|
||||||
[Obsolete("Only here for transition. Will be removed in future release. Use Library.Imaging.Image")]
|
|
||||||
[Table("image")]
|
|
||||||
public partial class Image : EntityBase
|
|
||||||
{
|
|
||||||
public Artist Artist { get; set; }
|
|
||||||
[Column("artistId")] public int? ArtistId { get; set; }
|
|
||||||
|
|
||||||
[Column("image", TypeName = "mediumblob")]
|
|
||||||
public byte[] Bytes { get; set; }
|
|
||||||
|
|
||||||
[Column("caption")] [MaxLength(100)] public string Caption { get; set; }
|
|
||||||
|
|
||||||
public Release Release { get; set; }
|
|
||||||
[Column("releaseId")] public int? ReleaseId { get; set; }
|
|
||||||
|
|
||||||
[Column("signature")] [MaxLength(50)] public string Signature { get; set; }
|
|
||||||
|
|
||||||
[Column("url")] [MaxLength(500)] public string Url { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,11 +20,12 @@
|
||||||
<PackageReference Include="LiteDB" Version="4.1.4" />
|
<PackageReference Include="LiteDB" Version="4.1.4" />
|
||||||
<PackageReference Include="Mapster" Version="4.1.1" />
|
<PackageReference Include="Mapster" Version="4.1.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.1" />
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.0" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.0" />
|
||||||
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
|
||||||
<PackageReference Include="Microsoft.PowerShell.SDK" Version="6.2.3" />
|
<PackageReference Include="Microsoft.PowerShell.SDK" Version="6.2.3" />
|
||||||
<PackageReference Include="MimeMapping" Version="1.0.1.17" />
|
<PackageReference Include="MimeMapping" Version="1.0.1.17" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
|
@ -35,7 +36,7 @@
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0007" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0007" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0007" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0007" />
|
||||||
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0009" />
|
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0009" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="4.6.0" />
|
<PackageReference Include="System.Drawing.Common" Version="4.6.1" />
|
||||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.6.0" />
|
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.6.0" />
|
||||||
<PackageReference Include="System.Runtime.Caching" Version="4.6.0" />
|
<PackageReference Include="System.Runtime.Caching" Version="4.6.0" />
|
||||||
<PackageReference Include="z440.atl.core" Version="2.13.0" />
|
<PackageReference Include="z440.atl.core" Version="2.13.0" />
|
||||||
|
@ -43,6 +44,9 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="FileContextCore">
|
||||||
|
<HintPath>..\libraries\FileContextCore.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="IdSharp.AudioInfo-core">
|
<Reference Include="IdSharp.AudioInfo-core">
|
||||||
<HintPath>..\libraries\IdSharp.AudioInfo-core.dll</HintPath>
|
<HintPath>..\libraries\IdSharp.AudioInfo-core.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
|
@ -1011,449 +1011,6 @@ namespace Roadie.Api.Services
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Migrate Storage from old folder structure to new folder structure.
|
|
||||||
/// </summary>
|
|
||||||
public async Task<OperationResult<bool>> MigrateStorage(ApplicationUser user, bool deleteEmptyFolders = true)
|
|
||||||
{
|
|
||||||
var sw = new Stopwatch();
|
|
||||||
sw.Start();
|
|
||||||
var errors = new List<Exception>();
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
|
|
||||||
var artistsMigrated = 0;
|
|
||||||
foreach (var artist in DbContext.Artists.Where(x => x.Status == Statuses.ReadyToMigrate).ToArray())
|
|
||||||
{
|
|
||||||
var oldArtistPath = FolderPathHelper.ArtistPathOld(Configuration, artist.SortNameValue);
|
|
||||||
var artistpath = FolderPathHelper.ArtistPath(Configuration, artist.Id, artist.SortNameValue);
|
|
||||||
|
|
||||||
if (Directory.Exists(oldArtistPath))
|
|
||||||
{
|
|
||||||
var artistInfoFile = new FileInfo(Path.Combine(oldArtistPath, "roadie.artist.json"));
|
|
||||||
if (artistInfoFile.Exists)
|
|
||||||
{
|
|
||||||
artistInfoFile.MoveTo(Path.Combine(artistpath, "roadie.artist.json"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var createdDirectory = false;
|
|
||||||
var filesMoved = 0;
|
|
||||||
var artistImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(oldArtistPath), ImageType.Artist);
|
|
||||||
var artistSecondaryImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(oldArtistPath), ImageType.ArtistSecondary).ToList();
|
|
||||||
if (artistImages.Any())
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(artistpath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(artistpath);
|
|
||||||
createdDirectory = true;
|
|
||||||
}
|
|
||||||
var artistToMergeIntoPrimaryImage = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistpath), ImageType.Artist).FirstOrDefault();
|
|
||||||
if (artistToMergeIntoPrimaryImage != null)
|
|
||||||
{
|
|
||||||
artistSecondaryImages.Add(artistImages.First());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var artistImageFilename = Path.Combine(artistpath, ImageHelper.ArtistImageFilename);
|
|
||||||
artistImages.First().MoveTo(artistImageFilename, true);
|
|
||||||
filesMoved++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (artistSecondaryImages.Any())
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(artistpath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(artistpath);
|
|
||||||
createdDirectory = true;
|
|
||||||
}
|
|
||||||
var looper = 0;
|
|
||||||
foreach (var artistSecondaryImage in artistSecondaryImages)
|
|
||||||
{
|
|
||||||
var artistImageFilename = Path.Combine(artistpath, string.Format(ImageHelper.ArtistSecondaryImageFilename, looper.ToString("00")));
|
|
||||||
while (File.Exists(artistImageFilename))
|
|
||||||
{
|
|
||||||
looper++;
|
|
||||||
artistImageFilename = Path.Combine(artistpath, string.Format(ImageHelper.ArtistSecondaryImageFilename, looper.ToString("00")));
|
|
||||||
}
|
|
||||||
artistSecondaryImage.MoveTo(artistImageFilename, true);
|
|
||||||
filesMoved++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
artist.Status = Statuses.Migrated;
|
|
||||||
artist.LastUpdated = now;
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
Logger.LogInformation($"Migrated Artist Storage `{ artist}` From [{ oldArtistPath }] => [{ artistpath }]");
|
|
||||||
artistsMigrated++;
|
|
||||||
}
|
|
||||||
Logger.LogInformation($"Artist Migration Complete. Migrated [{ artistsMigrated }] Artists.");
|
|
||||||
|
|
||||||
var labelsMigrated = 0;
|
|
||||||
foreach (var label in DbContext.Labels.Where(x => x.Status == Statuses.ReadyToMigrate).ToArray())
|
|
||||||
{
|
|
||||||
var oldLabelImageFileName = label.OldPathToImage(Configuration);
|
|
||||||
var labelImageFileName = label.PathToImage(Configuration);
|
|
||||||
if(File.Exists(oldLabelImageFileName))
|
|
||||||
{
|
|
||||||
var labelFileInfo = new FileInfo(labelImageFileName);
|
|
||||||
if(!labelFileInfo.Directory.Exists)
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(labelFileInfo.Directory.FullName);
|
|
||||||
}
|
|
||||||
File.Move(oldLabelImageFileName, labelImageFileName, true);
|
|
||||||
label.Status = Statuses.Migrated;
|
|
||||||
label.LastUpdated = now;
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
Logger.LogInformation($"Migrated Label Storage `{ label}` From [{ oldLabelImageFileName }] => [{ labelImageFileName }]");
|
|
||||||
labelsMigrated++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Logger.LogInformation($"Label Migration Complete. Migrated [{ labelsMigrated }] Labels.");
|
|
||||||
|
|
||||||
var genresMigrated = 0;
|
|
||||||
foreach (var genre in DbContext.Genres.Where(x => x.Status == Statuses.ReadyToMigrate).ToArray())
|
|
||||||
{
|
|
||||||
var oldGenreImageFileName = genre.OldPathToImage(Configuration);
|
|
||||||
var genreImageFileName = genre.PathToImage(Configuration);
|
|
||||||
if (File.Exists(oldGenreImageFileName))
|
|
||||||
{
|
|
||||||
var genreFileInfo = new FileInfo(genreImageFileName);
|
|
||||||
if (!genreFileInfo.Directory.Exists)
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(genreFileInfo.Directory.FullName);
|
|
||||||
}
|
|
||||||
File.Move(oldGenreImageFileName, genreImageFileName, true);
|
|
||||||
genre.Status = Statuses.Migrated;
|
|
||||||
genre.LastUpdated = now;
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
Logger.LogInformation($"Migrated Genre Storage `{ genre}` From [{ oldGenreImageFileName }] => [{ genreImageFileName }]");
|
|
||||||
genresMigrated++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Logger.LogInformation($"Genre Migration Complete. Migrated [{ genresMigrated }] Genres.");
|
|
||||||
|
|
||||||
var releases = DbContext.Releases
|
|
||||||
.Include(x => x.Artist)
|
|
||||||
.Include(x => x.Medias)
|
|
||||||
.Where(x => x.Status == Statuses.ReadyToMigrate)
|
|
||||||
.ToArray();
|
|
||||||
var releasesMigrated = 0;
|
|
||||||
foreach (var release in releases)
|
|
||||||
{
|
|
||||||
var oldArtistPath = FolderPathHelper.ArtistPathOld(Configuration, release.Artist.SortNameValue);
|
|
||||||
var oldReleasePath = FolderPathHelper.ReleasePathOld(oldArtistPath, release.SortTitleValue, release.ReleaseDate.Value);
|
|
||||||
|
|
||||||
var artistpath = FolderPathHelper.ArtistPath(Configuration, release.Artist.Id, release.Artist.SortNameValue);
|
|
||||||
var releasePath = FolderPathHelper.ReleasePath(artistpath, release.SortTitleValue, release.ReleaseDate.Value);
|
|
||||||
|
|
||||||
if (!Directory.Exists(artistpath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(artistpath);
|
|
||||||
}
|
|
||||||
if (!Directory.Exists(releasePath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(releasePath);
|
|
||||||
}
|
|
||||||
var releaseTracks = (from r in DbContext.Releases
|
|
||||||
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
|
||||||
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
|
|
||||||
where r.Id == release.Id
|
|
||||||
where t.FileName != null
|
|
||||||
select t).ToArray();
|
|
||||||
|
|
||||||
foreach(var releaseTrack in releaseTracks)
|
|
||||||
{
|
|
||||||
var oldTrackFileName = Path.Combine(oldReleasePath, releaseTrack.FileName);
|
|
||||||
var newTrackFileName = Path.Combine(releasePath, releaseTrack.FileName.ToFileNameFriendly());
|
|
||||||
if(File.Exists(oldTrackFileName))
|
|
||||||
{
|
|
||||||
File.Move(oldTrackFileName, newTrackFileName, true);
|
|
||||||
releaseTrack.FilePath = FolderPathHelper.TrackPath(Configuration, release.Artist, release, releaseTrack);
|
|
||||||
releaseTrack.FileName = releaseTrack.FileName.ToFileNameFriendly();
|
|
||||||
releaseTrack.LastUpdated = now;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.LogWarning($"Migration: Track `{ releaseTrack }` Track File [{ oldTrackFileName }] Not Found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var releaseInfoFile = new FileInfo(Path.Combine(oldReleasePath, "roadie.albuminfo.json"));
|
|
||||||
if(releaseInfoFile.Exists)
|
|
||||||
{
|
|
||||||
releaseInfoFile.MoveTo(Path.Combine(releasePath, "roadie.releaseinfo.json"));
|
|
||||||
}
|
|
||||||
var releaseToMergeImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(oldReleasePath), ImageType.Release);
|
|
||||||
var releaseToMergeSecondaryImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(oldReleasePath), ImageType.ReleaseSecondary).ToList();
|
|
||||||
if (releaseToMergeImages.Any())
|
|
||||||
{
|
|
||||||
var releaseToMergeIntoPrimaryImage = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releasePath), ImageType.Release).FirstOrDefault();
|
|
||||||
if (releaseToMergeIntoPrimaryImage != null)
|
|
||||||
{
|
|
||||||
releaseToMergeSecondaryImages.Add(releaseToMergeImages.First());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var releaseImageFilename = Path.Combine(releasePath, ImageHelper.ReleaseCoverFilename);
|
|
||||||
releaseToMergeImages.First().MoveTo(releaseImageFilename, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (releaseToMergeSecondaryImages.Any())
|
|
||||||
{
|
|
||||||
var looper = 0;
|
|
||||||
foreach (var releaseSecondaryImage in releaseToMergeSecondaryImages)
|
|
||||||
{
|
|
||||||
var releaseImageFilename = Path.Combine(releasePath, string.Format(ImageHelper.ReleaseSecondaryImageFilename, looper.ToString("00")));
|
|
||||||
while (File.Exists(releaseImageFilename))
|
|
||||||
{
|
|
||||||
looper++;
|
|
||||||
releaseImageFilename = Path.Combine(releasePath, string.Format(ImageHelper.ReleaseSecondaryImageFilename, looper.ToString("00")));
|
|
||||||
}
|
|
||||||
releaseSecondaryImage.MoveTo(releaseImageFilename, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
release.Status = Statuses.Migrated;
|
|
||||||
release.LastUpdated = now;
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
Logger.LogInformation($"Migrated Release `{ release}` From [{ oldReleasePath }] => [{ releasePath }]");
|
|
||||||
releasesMigrated++;
|
|
||||||
}
|
|
||||||
Logger.LogInformation($"Release Migration Complete. Migrated [{ releasesMigrated }] Releases.");
|
|
||||||
|
|
||||||
if (deleteEmptyFolders)
|
|
||||||
{
|
|
||||||
Logger.LogInformation($"Deleting Empty Folders in Library [{ Configuration.LibraryFolder }] Folder.");
|
|
||||||
Services.FileDirectoryProcessorService.DeleteEmptyFolders(new DirectoryInfo(Configuration.LibraryFolder), Logger);
|
|
||||||
}
|
|
||||||
CacheManager.Clear();
|
|
||||||
|
|
||||||
return new OperationResult<bool>
|
|
||||||
{
|
|
||||||
IsSuccess = !errors.Any(),
|
|
||||||
Data = true,
|
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
|
||||||
Errors = errors
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Migrate images from Images table and Thumbnails to file storage.
|
|
||||||
/// </summary>
|
|
||||||
public async Task<OperationResult<bool>> MigrateImages(ApplicationUser user)
|
|
||||||
{
|
|
||||||
var sw = new Stopwatch();
|
|
||||||
sw.Start();
|
|
||||||
var errors = new List<Exception>();
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
foreach (var artist in DbContext.Artists.Where(x => x.Thumbnail != null).OrderBy(x => x.SortName ?? x.Name))
|
|
||||||
{
|
|
||||||
var artistFolder = artist.ArtistFileFolder(Configuration);
|
|
||||||
if (!Directory.Exists(artistFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(artistFolder);
|
|
||||||
}
|
|
||||||
var artistImage = Path.Combine(artistFolder, ImageHelper.ArtistImageFilename);
|
|
||||||
if (!File.Exists(artistImage))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(artistImage, ImageHelper.ConvertToJpegFormat(artist.Thumbnail));
|
|
||||||
}
|
|
||||||
artist.Thumbnail = null;
|
|
||||||
artist.LastUpdated = now;
|
|
||||||
|
|
||||||
Logger.LogInformation($"Saved Artist Image `{artist}` path [{ artistImage }]");
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
var artistImages = (from i in DbContext.Images
|
|
||||||
join a in DbContext.Artists on i.ArtistId equals a.Id
|
|
||||||
select new { i, a });
|
|
||||||
foreach (var artistImage in artistImages)
|
|
||||||
{
|
|
||||||
var looper = 0;
|
|
||||||
var artistFolder = artistImage.a.ArtistFileFolder(Configuration);
|
|
||||||
var artistImageFilename = Path.Combine(artistFolder, string.Format(ImageHelper.ArtistSecondaryImageFilename, looper.ToString("00")));
|
|
||||||
while (File.Exists(artistImageFilename))
|
|
||||||
{
|
|
||||||
looper++;
|
|
||||||
artistImageFilename = Path.Combine(artistFolder, string.Format(ImageHelper.ArtistSecondaryImageFilename, looper.ToString("00")));
|
|
||||||
}
|
|
||||||
File.WriteAllBytes(artistImageFilename, ImageHelper.ConvertToJpegFormat(artistImage.i.Bytes));
|
|
||||||
DbContext.Images.Remove(artistImage.i);
|
|
||||||
Logger.LogInformation($"Saved Artist Secondary Image `{artistImage.a}` path [{ artistImageFilename }]");
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var collection in DbContext.Collections.Where(x => x.Thumbnail != null).OrderBy(x => x.SortName ?? x.Name))
|
|
||||||
{
|
|
||||||
var image = collection.PathToImage(Configuration);
|
|
||||||
if (!File.Exists(image))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(image, ImageHelper.ConvertToJpegFormat(collection.Thumbnail));
|
|
||||||
}
|
|
||||||
collection.Thumbnail = null;
|
|
||||||
collection.LastUpdated = now;
|
|
||||||
Logger.LogInformation($"Saved Collection Image `{collection}` path [{ image }]");
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var genre in DbContext.Genres.Where(x => x.Thumbnail != null).OrderBy(x => x.Name))
|
|
||||||
{
|
|
||||||
var image = genre.PathToImage(Configuration);
|
|
||||||
if (!File.Exists(image))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(image, ImageHelper.ConvertToJpegFormat(genre.Thumbnail));
|
|
||||||
}
|
|
||||||
genre.Thumbnail = null;
|
|
||||||
genre.LastUpdated = now;
|
|
||||||
Logger.LogInformation($"Saved Genre Image `{genre}` path [{ image }]");
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var label in DbContext.Labels.Where(x => x.Thumbnail != null).OrderBy(x => x.SortName ?? x.Name))
|
|
||||||
{
|
|
||||||
var image = label.PathToImage(Configuration);
|
|
||||||
if (!File.Exists(image))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(image, ImageHelper.ConvertToJpegFormat(label.Thumbnail));
|
|
||||||
}
|
|
||||||
label.Thumbnail = null;
|
|
||||||
label.LastUpdated = now;
|
|
||||||
Logger.LogInformation($"Saved Label Image `{label}` path [{ image }]");
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var playlist in DbContext.Playlists.Where(x => x.Thumbnail != null).OrderBy(x => x.Name))
|
|
||||||
{
|
|
||||||
var image = playlist.PathToImage(Configuration);
|
|
||||||
if (!File.Exists(image))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(image, ImageHelper.ConvertToJpegFormat(playlist.Thumbnail));
|
|
||||||
}
|
|
||||||
playlist.Thumbnail = null;
|
|
||||||
playlist.LastUpdated = now;
|
|
||||||
Logger.LogInformation($"Saved Playlist Image `{playlist}` path [{ image }]");
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var release in DbContext.Releases.Include(x => x.Artist).Where(x => x.Thumbnail != null).OrderBy(x => x.SortTitle ?? x.Title))
|
|
||||||
{
|
|
||||||
var artistFolder = release.Artist.ArtistFileFolder(Configuration);
|
|
||||||
if (!Directory.Exists(artistFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(artistFolder);
|
|
||||||
}
|
|
||||||
var releaseFolder = release.ReleaseFileFolder(artistFolder);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(releaseFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(releaseFolder);
|
|
||||||
}
|
|
||||||
var releaseImage = Path.Combine(releaseFolder, "cover.jpg");
|
|
||||||
if (!File.Exists(releaseImage))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(releaseImage, ImageHelper.ConvertToJpegFormat(release.Thumbnail));
|
|
||||||
}
|
|
||||||
release.Thumbnail = null;
|
|
||||||
release.LastUpdated = now;
|
|
||||||
Logger.LogInformation($"Saved Release Image `{release}` path [{ releaseImage }]");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex, $"Error saving Release Image `{release}` folder [{ releaseFolder }]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
var releaseImages = (from i in DbContext.Images
|
|
||||||
join r in DbContext.Releases.Include(x => x.Artist) on i.ReleaseId equals r.Id
|
|
||||||
select new { i, r });
|
|
||||||
foreach (var releaseImage in releaseImages)
|
|
||||||
{
|
|
||||||
var looper = 0;
|
|
||||||
var artistFolder = releaseImage.r.Artist.ArtistFileFolder(Configuration);
|
|
||||||
if (!Directory.Exists(artistFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(artistFolder);
|
|
||||||
}
|
|
||||||
var releaseFolder = releaseImage.r.ReleaseFileFolder(artistFolder);
|
|
||||||
if (!Directory.Exists(releaseFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(releaseFolder);
|
|
||||||
}
|
|
||||||
var releaseImageFilename = Path.Combine(releaseFolder, string.Format(ImageHelper.ReleaseSecondaryImageFilename, looper.ToString("00")));
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (File.Exists(releaseImageFilename))
|
|
||||||
{
|
|
||||||
looper++;
|
|
||||||
releaseImageFilename = Path.Combine(releaseFolder, string.Format(ImageHelper.ReleaseSecondaryImageFilename, looper.ToString("00")));
|
|
||||||
}
|
|
||||||
File.WriteAllBytes(releaseImageFilename, ImageHelper.ConvertToJpegFormat(releaseImage.i.Bytes));
|
|
||||||
DbContext.Images.Remove(releaseImage.i);
|
|
||||||
Logger.LogInformation($"Saved Release Secondary Image `{releaseImage.r}` path [{ releaseImageFilename }]");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex, $"Error saving Release Secondary Image [{releaseImageFilename}] folder [{ releaseFolder }]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var track in DbContext.Tracks.Include(x => x.ReleaseMedia)
|
|
||||||
.Include(x => x.ReleaseMedia.Release)
|
|
||||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
|
||||||
.Where(x => x.Thumbnail != null).OrderBy(x => x.Title))
|
|
||||||
{
|
|
||||||
var artistFolder = track.ReleaseMedia.Release.Artist.ArtistFileFolder(Configuration);
|
|
||||||
if (!Directory.Exists(artistFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(artistFolder);
|
|
||||||
}
|
|
||||||
var releaseFolder = track.ReleaseMedia.Release.ReleaseFileFolder(artistFolder);
|
|
||||||
if (!Directory.Exists(releaseFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(releaseFolder);
|
|
||||||
}
|
|
||||||
var trackImage = track.PathToTrackThumbnail(Configuration);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!File.Exists(trackImage))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(trackImage, ImageHelper.ConvertToJpegFormat(track.Thumbnail));
|
|
||||||
}
|
|
||||||
track.Thumbnail = null;
|
|
||||||
track.LastUpdated = now;
|
|
||||||
Logger.LogInformation($"Saved Track Image `{track}` path [{ trackImage }]");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex, $"Error saving Track Image [{trackImage}] folder [{ releaseFolder }]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var usr in DbContext.Users.Where(x => x.Avatar != null).OrderBy(x => x.UserName))
|
|
||||||
{
|
|
||||||
var image = usr.PathToImage(Configuration);
|
|
||||||
if (!File.Exists(image))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(image, ImageHelper.ConvertToJpegFormat(usr.Avatar));
|
|
||||||
}
|
|
||||||
usr.Avatar = null;
|
|
||||||
usr.LastUpdated = now;
|
|
||||||
Logger.LogInformation($"Saved User Image `{user}` path [{ image }]");
|
|
||||||
}
|
|
||||||
await DbContext.SaveChangesAsync();
|
|
||||||
|
|
||||||
return new OperationResult<bool>
|
|
||||||
{
|
|
||||||
IsSuccess = !errors.Any(),
|
|
||||||
Data = true,
|
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
|
||||||
Errors = errors
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId)
|
public async Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId)
|
||||||
{
|
{
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
|
|
|
@ -52,9 +52,5 @@ namespace Roadie.Api.Services
|
||||||
Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId);
|
Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId);
|
||||||
|
|
||||||
Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId);
|
Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId);
|
||||||
|
|
||||||
Task<OperationResult<bool>> MigrateImages(ApplicationUser user);
|
|
||||||
|
|
||||||
Task<OperationResult<bool>> MigrateStorage(ApplicationUser user, bool deleteEmptyFolders);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -319,7 +319,7 @@ namespace Roadie.Api.Services
|
||||||
if (labelImage != null)
|
if (labelImage != null)
|
||||||
{
|
{
|
||||||
// Save unaltered label image
|
// Save unaltered label image
|
||||||
File.WriteAllBytes(label.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(labelImage));
|
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(labelImage));
|
||||||
}
|
}
|
||||||
label.LastUpdated = now;
|
label.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync();
|
||||||
|
|
|
@ -209,21 +209,23 @@ namespace Roadie.Api.Services
|
||||||
year = SafeParser.ToNumber<int>(x.Key),
|
year = SafeParser.ToNumber<int>(x.Key),
|
||||||
count = x.Count()
|
count = x.Count()
|
||||||
});
|
});
|
||||||
|
if (decadeInfos != null && decadeInfos.Any())
|
||||||
var decadeInterval = 10;
|
|
||||||
var startingDecade = (decadeInfos.Min(x => x.year) / 10) * 10;
|
|
||||||
var endingDecade = (decadeInfos.Max(x => x.year) / 10) * 10;
|
|
||||||
for (int decade = startingDecade; decade <= endingDecade; decade += decadeInterval)
|
|
||||||
{
|
{
|
||||||
var endOfDecade = decade + 9;
|
var decadeInterval = 10;
|
||||||
var count = decadeInfos.Where(x => x.year >= decade && x.year <= endOfDecade).Sum(x => x.count);
|
var startingDecade = (decadeInfos.Min(x => x.year) / 10) * 10;
|
||||||
if (count > 0)
|
var endingDecade = (decadeInfos.Max(x => x.year) / 10) * 10;
|
||||||
|
for (int decade = startingDecade; decade <= endingDecade; decade += decadeInterval)
|
||||||
{
|
{
|
||||||
result.Add(new DateAndCount
|
var endOfDecade = decade + 9;
|
||||||
|
var count = decadeInfos.Where(x => x.year >= decade && x.year <= endOfDecade).Sum(x => x.count);
|
||||||
|
if (count > 0)
|
||||||
{
|
{
|
||||||
Date = decade.ToString(),
|
result.Add(new DateAndCount
|
||||||
Count = count
|
{
|
||||||
});
|
Date = decade.ToString(),
|
||||||
|
Count = count
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
|
|
@ -338,37 +338,5 @@ namespace Roadie.Api.Controllers
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("migrateimages")]
|
|
||||||
[ProducesResponseType(200)]
|
|
||||||
public async Task<IActionResult> MigrateImages()
|
|
||||||
{
|
|
||||||
var result = await AdminService.MigrateImages(await UserManager.GetUserAsync(User));
|
|
||||||
if (!result.IsSuccess)
|
|
||||||
{
|
|
||||||
if (result.Messages?.Any() ?? false)
|
|
||||||
{
|
|
||||||
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
|
|
||||||
}
|
|
||||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
|
||||||
}
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[HttpPost("migratestorage")]
|
|
||||||
[ProducesResponseType(200)]
|
|
||||||
public async Task<IActionResult> MigrateStorage(bool? deleteEmptyFolders)
|
|
||||||
{
|
|
||||||
var result = await AdminService.MigrateStorage(await UserManager.GetUserAsync(User), deleteEmptyFolders ?? true);
|
|
||||||
if (!result.IsSuccess)
|
|
||||||
{
|
|
||||||
if (result.Messages?.Any() ?? false)
|
|
||||||
{
|
|
||||||
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
|
|
||||||
}
|
|
||||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
|
||||||
}
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -30,7 +30,8 @@
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.3.1" />
|
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.3.1" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.3.1" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.3.1" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.3.1" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.3.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.1" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
|
||||||
|
@ -56,4 +57,10 @@
|
||||||
<ProjectReference Include="..\Roadie.Dlna.Services\Roadie.Dlna.Services.csproj" />
|
<ProjectReference Include="..\Roadie.Dlna.Services\Roadie.Dlna.Services.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FileContextCore">
|
||||||
|
<HintPath>..\libraries\FileContextCore.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#region Usings
|
#region Usings
|
||||||
|
|
||||||
|
using FileContextCore;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
@ -57,14 +58,6 @@ namespace Roadie.Api
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
TypeAdapterConfig<Library.Data.Image, Library.Models.Image>
|
|
||||||
.NewConfig()
|
|
||||||
.Map(i => i.ArtistId,
|
|
||||||
src => src.Artist == null ? null : (Guid?)src.Artist.RoadieId)
|
|
||||||
.Map(i => i.ReleaseId,
|
|
||||||
src => src.Release == null ? null : (Guid?)src.Release.RoadieId)
|
|
||||||
.Compile();
|
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.PreserveReference(true);
|
TypeAdapterConfig.GlobalSettings.Default.PreserveReference(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +98,10 @@ namespace Roadie.Api
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
var settings = new RoadieSettings();
|
||||||
|
_configuration.GetSection("RoadieSettings").Bind(settings);
|
||||||
|
|
||||||
services.AddSingleton<ITokenService, TokenService>();
|
services.AddSingleton<ITokenService, TokenService>();
|
||||||
services.AddSingleton<IHttpEncoder, HttpEncoder>();
|
services.AddSingleton<IHttpEncoder, HttpEncoder>();
|
||||||
services.AddSingleton<IEmailSender, EmailSenderService>();
|
services.AddSingleton<IEmailSender, EmailSenderService>();
|
||||||
|
@ -115,29 +112,47 @@ namespace Roadie.Api
|
||||||
return new MemoryCacheManager(logger, new CachePolicy(TimeSpan.FromHours(4)));
|
return new MemoryCacheManager(logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddDbContextPool<ApplicationUserDbContext>(
|
switch (settings.DbContextToUse)
|
||||||
options => options.UseMySql(_configuration.GetConnectionString("RoadieDatabaseConnection"),
|
{
|
||||||
mySqlOptions =>
|
case DbContexts.MySQL:
|
||||||
{
|
services.AddDbContextPool<ApplicationUserDbContext>(
|
||||||
mySqlOptions.ServerVersion(new Version(5, 5), ServerType.MariaDb);
|
options => options.UseMySql(_configuration.GetConnectionString("RoadieDatabaseConnection"),
|
||||||
mySqlOptions.EnableRetryOnFailure(
|
mySqlOptions =>
|
||||||
10,
|
{
|
||||||
TimeSpan.FromSeconds(30),
|
mySqlOptions.ServerVersion(new Version(5, 5), ServerType.MariaDb);
|
||||||
null);
|
mySqlOptions.EnableRetryOnFailure(
|
||||||
}
|
10,
|
||||||
));
|
TimeSpan.FromSeconds(30),
|
||||||
|
null);
|
||||||
services.AddDbContextPool<IRoadieDbContext, MySQLRoadieDbContext>(
|
}
|
||||||
options => options.UseMySql(_configuration.GetConnectionString("RoadieDatabaseConnection"),
|
));
|
||||||
mySqlOptions =>
|
services.AddDbContextPool<IRoadieDbContext, MySQLRoadieDbContext>(
|
||||||
{
|
options => options.UseMySql(_configuration.GetConnectionString("RoadieDatabaseConnection"),
|
||||||
mySqlOptions.ServerVersion(new Version(5, 5), ServerType.MariaDb);
|
mySqlOptions =>
|
||||||
mySqlOptions.EnableRetryOnFailure(
|
{
|
||||||
10,
|
mySqlOptions.ServerVersion(new Version(5, 5), ServerType.MariaDb);
|
||||||
TimeSpan.FromSeconds(30),
|
mySqlOptions.EnableRetryOnFailure(
|
||||||
null);
|
10,
|
||||||
}
|
TimeSpan.FromSeconds(30),
|
||||||
));
|
null);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case DbContexts.File:
|
||||||
|
services.AddDbContext<ApplicationUserDbContext>(
|
||||||
|
options => options.UseFileContextDatabase(settings.FileDatabaseOptions.DatabaseFormat.ToString().ToLower(),
|
||||||
|
databaseName: settings.FileDatabaseOptions.DatabaseName,
|
||||||
|
location: settings.FileDatabaseOptions.DatabaseFolder)
|
||||||
|
);
|
||||||
|
services.AddDbContext<IRoadieDbContext, FileRoadieDbContext>(
|
||||||
|
options => options.UseFileContextDatabase(settings.FileDatabaseOptions.DatabaseFormat.ToString().ToLower(),
|
||||||
|
databaseName: settings.FileDatabaseOptions.DatabaseName,
|
||||||
|
location: settings.FileDatabaseOptions.DatabaseFolder)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException("Unknown DbContext Type");
|
||||||
|
}
|
||||||
|
|
||||||
services.AddIdentity<ApplicationUser, ApplicationRole>()
|
services.AddIdentity<ApplicationUser, ApplicationRole>()
|
||||||
.AddRoles<ApplicationRole>()
|
.AddRoles<ApplicationRole>()
|
||||||
|
|
|
@ -59,8 +59,12 @@
|
||||||
},
|
},
|
||||||
"CORSOrigins": "http://localhost:4200|http://localhost:8080|https://localhost:8080|http://localhost:80|https://localhost:80|http://192.168.1.177:8080",
|
"CORSOrigins": "http://localhost:4200|http://localhost:8080|https://localhost:8080|http://localhost:80|https://localhost:80|http://192.168.1.177:8080",
|
||||||
"RoadieSettings": {
|
"RoadieSettings": {
|
||||||
|
"DbContextToUse": "File",
|
||||||
|
"FileDatabaseOptions": {
|
||||||
|
"DatabaseFolder": "C:\\\\roadie_dev_root\\\\db"
|
||||||
|
},
|
||||||
"InboundFolder": "C:\\roadie_dev_root\\inbound",
|
"InboundFolder": "C:\\roadie_dev_root\\inbound",
|
||||||
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
|
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
|
||||||
"Dlna": {
|
"Dlna": {
|
||||||
"IsEnabled": false
|
"IsEnabled": false
|
||||||
},
|
},
|
||||||
|
|
BIN
libraries/FileContextCore.dll
Normal file
BIN
libraries/FileContextCore.dll
Normal file
Binary file not shown.
Loading…
Reference in a new issue