Halo heisst ab hier Flaro — die Marke stand im Weg

Der Upload zu App Store Connect scheiterte am Namen. „Halo" ist eine
eingetragene Marke von Microsoft; im App Store heisst zwar keine App exakt
so, aber reservierte und markenrechtlich belegte Namen tauchen in keiner
Suche auf. Der einzige verlässliche Test war die Eingabe dort, und die ging
daneben.

**Der Name wurde diesmal vorher geprüft.** Zwanzig Kandidaten gegen den
deutschen und amerikanischen App Store, auf exakte Treffer und auf ähnliche
Namen. „Kavo" wäre dieselbe Wand gewesen — exakt belegt in beiden Stores, in
Deutschland von KaVo Dental GmbH. „Flare" ist mit 42 ähnlichen Apps je Store
der am dichtesten besetzte Name der ganzen Runde. **Flaro** ist in beiden
frei und liest sich als eigenes Wort, nicht als Flare mit Tippfehler.

Das bleibt eine Store-Suche und keine Markenrecherche — reservierte Namen
ohne veröffentlichte App sieht sie nicht. Aber es ist mehr Prüfung, als beim
letzten Mal stattfand.

---

2160 Textvorkommen in 273 Dateien, 49 Pfade. Betroffen ist diesmal auch der
Server: `Flaro.Api`, `Flaro.Core`, `Flaro.Data`, `Flaro.Media`,
`Flaro.Metadata`, `FlaroContext`, `FlaroPaths`, `flaro.db`, die Variablen
`FLARO_DATA`, `FLARO_CACHE`, `FLARO_TRANSCODE`, `FLARO_WRITE_SIDECARS`, und
das Image.

**Vor dem Ersetzen geprüft**, ob „halo" irgendwo als Teil eines anderen
Wortes steckt — und ob es im TMDB-Token vorkommt. Tat es nicht; ein blindes
Ersetzen hätte den sonst zerlegt.

`docs/superpowers/specs/` bleibt wie beim letzten Mal unangetastet: datierte
Entwurfsdokumente sind ein Protokoll getroffener Entscheidungen. Das
Server-Dokument hat stattdessen einen Nachtrag bekommen, damit es niemanden
in die Irre führt.

**Die Bundle-ID wandert mit**, zum zweiten Mal an einem Tag:
`com.scarriffleservices.flaro`. Wer die vorige Fassung installiert hat, hat
jetzt zwei Karteileichen auf dem Gerät — beide löschen, dann ist Ruhe.

308 Server-Tests grün, 368 im Swift-Paket, null Warnungen. iOS und tvOS
bauen, das Image baut, und ein frischer Container läuft durch Einrichtung
und Anmeldung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-03 19:38:27 +02:00
co-authored by Claude Opus 5
parent f98b995050
commit a7cf6c5def
390 changed files with 2078 additions and 2069 deletions
@@ -1,12 +1,12 @@
using System.Security.Claims;
using System.Text.Encodings.Web;
using Halo.Core.Auth;
using Halo.Data;
using Flaro.Core.Auth;
using Flaro.Data;
using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace Halo.Api.Auth;
namespace Flaro.Api.Auth;
/// <summary>Weist Anfragen über ein Geräte-Token aus.</summary>
///
@@ -26,11 +26,11 @@ public sealed class TokenAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
HaloContext db,
FlaroContext db,
TimeProvider clock) : AuthenticationHandler<AuthenticationSchemeOptions>(options, logger, encoder)
{
public const string SchemeName = "HaloToken";
public const string DeviceTokenIdClaim = "halo:device";
public const string SchemeName = "FlaroToken";
public const string DeviceTokenIdClaim = "flaro:device";
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
@@ -66,14 +66,14 @@ public sealed class TokenAuthenticationHandler(
new Claim(ClaimTypes.NameIdentifier, benutzer.Id.ToString()),
new Claim(ClaimTypes.Name, benutzer.UserName),
new Claim(DeviceTokenIdClaim, eintrag.Id.ToString()),
.. benutzer.IsAdministrator ? new[] { new Claim(ClaimTypes.Role, HaloRoles.Administrator) } : [],
.. benutzer.IsAdministrator ? new[] { new Claim(ClaimTypes.Role, FlaroRoles.Administrator) } : [],
], SchemeName);
return AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(ausweis), SchemeName));
}
}
public static class HaloRoles
public static class FlaroRoles
{
public const string Administrator = "administrator";
}
@@ -1,11 +1,11 @@
using System.Security.Claims;
using Halo.Api.Auth;
using Halo.Core.Auth;
using Halo.Core.Users;
using Halo.Data;
using Flaro.Api.Auth;
using Flaro.Core.Auth;
using Flaro.Core.Users;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
public static class AuthEndpoints
{
@@ -23,7 +23,7 @@ public static class AuthEndpoints
public static void MapAuth(this IEndpointRouteBuilder app)
{
app.MapPost("/api/v1/auth/login", async (
LoginRequest anfrage, HaloContext db, TimeProvider clock) =>
LoginRequest anfrage, FlaroContext db, TimeProvider clock) =>
{
var name = anfrage.UserName.Trim();
var benutzer = await db.Users.FirstOrDefaultAsync(u => u.UserName == name);
@@ -46,9 +46,9 @@ public static class AuthEndpoints
var antwort = await TokenAusstellen(db, clock, benutzer, anfrage.DeviceName, anfrage.DeviceId);
await db.SaveChangesAsync();
return Results.Ok(antwort);
}).AllowAnonymous().RequireRateLimiting(HaloRateLimits.SignIn);
}).AllowAnonymous().RequireRateLimiting(FlaroRateLimits.SignIn);
app.MapPost("/api/v1/auth/logout", async (ClaimsPrincipal wer, HaloContext db, TimeProvider clock) =>
app.MapPost("/api/v1/auth/logout", async (ClaimsPrincipal wer, FlaroContext db, TimeProvider clock) =>
{
if (!Guid.TryParse(wer.FindFirstValue(TokenAuthenticationHandler.DeviceTokenIdClaim), out var id))
return Results.Unauthorized();
@@ -67,7 +67,7 @@ public static class AuthEndpoints
? Results.Ok(new AuthenticatedUser(
id,
wer.FindFirstValue(ClaimTypes.Name) ?? "",
wer.IsInRole(HaloRoles.Administrator)))
wer.IsInRole(FlaroRoles.Administrator)))
: Results.Unauthorized())
.RequireAuthorization();
@@ -77,7 +77,7 @@ public static class AuthEndpoints
/// <summary>Anmelden mit einem Code auf dem Bildschirm.</summary>
private static void MapCodeFlow(IEndpointRouteBuilder app)
{
app.MapPost("/api/v1/auth/code", async (CodeRequest anfrage, HaloContext db, TimeProvider clock) =>
app.MapPost("/api/v1/auth/code", async (CodeRequest anfrage, FlaroContext db, TimeProvider clock) =>
{
var jetzt = clock.GetUtcNow();
@@ -99,10 +99,10 @@ public static class AuthEndpoints
await db.SaveChangesAsync();
return Results.Ok(new CodeResponse(code.Code, abholschein, code.ExpiresAt));
}).AllowAnonymous().RequireRateLimiting(HaloRateLimits.SignIn);
}).AllowAnonymous().RequireRateLimiting(FlaroRateLimits.SignIn);
app.MapGet("/api/v1/auth/code/{handle}", async (
string handle, HaloContext db, TimeProvider clock) =>
string handle, FlaroContext db, TimeProvider clock) =>
{
var jetzt = clock.GetUtcNow();
var fingerabdruck = Secrets.Fingerprint(handle);
@@ -124,10 +124,10 @@ public static class AuthEndpoints
await db.SaveChangesAsync();
return Results.Ok(new CodeState("approved", antwort));
}).AllowAnonymous().RequireRateLimiting(HaloRateLimits.Polling);
}).AllowAnonymous().RequireRateLimiting(FlaroRateLimits.Polling);
app.MapPost("/api/v1/auth/code/{code}", async (
string code, ClaimsPrincipal wer, HaloContext db, TimeProvider clock) =>
string code, ClaimsPrincipal wer, FlaroContext db, TimeProvider clock) =>
{
if (!Guid.TryParse(wer.FindFirstValue(ClaimTypes.NameIdentifier), out var benutzerId))
return Results.Unauthorized();
@@ -144,7 +144,7 @@ public static class AuthEndpoints
// Damit am Telefon steht, was man da gerade hereinlässt.
return Results.Ok(new { device = offen.DeviceName });
}).RequireAuthorization().RequireRateLimiting(HaloRateLimits.SignIn);
}).RequireAuthorization().RequireRateLimiting(FlaroRateLimits.SignIn);
}
/// <summary>Stellt ein Geräte-Token aus und löst ein älteres desselben Geräts ab.</summary>
@@ -155,7 +155,7 @@ public static class AuthEndpoints
/// und nach einem Jahr weiss niemand mehr, welches Telefon welches ist.
/// </remarks>
private static async Task<LoginResponse> TokenAusstellen(
HaloContext db, TimeProvider clock, User benutzer, string geräteName, string geräteKennung)
FlaroContext db, TimeProvider clock, User benutzer, string geräteName, string geräteKennung)
{
var jetzt = clock.GetUtcNow();
var kennung = Kürzen(geräteKennung, 128);
@@ -1,4 +1,4 @@
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
// Was über die Leitung geht. Bewusst eigene Typen und nicht die der Domäne:
// sonst wandert jede Umbenennung im Datenmodell ungefragt in die Schnittstelle
@@ -1,16 +1,16 @@
using Halo.Core.Delivery;
using Halo.Core.Library;
using Halo.Data;
using Flaro.Core.Delivery;
using Flaro.Core.Library;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
public static class DeliveryEndpoints
{
public static void MapDelivery(this IEndpointRouteBuilder app)
{
app.MapGet("/api/v1/files/{id:guid}/delivery", async (
Guid id, HaloContext db, PackageCoordinator packer) =>
Guid id, FlaroContext db, PackageCoordinator packer) =>
{
var gefunden = await Laden(db, id);
if (gefunden is not var (datei, plan)) return Results.NotFound();
@@ -19,7 +19,7 @@ public static class DeliveryEndpoints
}).RequireAuthorization();
app.MapGet("/api/v1/files/{id:guid}/download", async (
Guid id, HaloContext db, PackageCoordinator packer) =>
Guid id, FlaroContext db, PackageCoordinator packer) =>
{
var gefunden = await Laden(db, id);
if (gefunden is not var (datei, plan)) return Results.NotFound();
@@ -64,7 +64,7 @@ public static class DeliveryEndpoints
}).RequireAuthorization();
}
private static async Task<(MediaFile Datei, DeliveryPlan Plan)?> Laden(HaloContext db, Guid id)
private static async Task<(MediaFile Datei, DeliveryPlan Plan)?> Laden(FlaroContext db, Guid id)
{
var datei = await db.MediaFiles.AsNoTracking().FirstOrDefaultAsync(f => f.Id == id);
if (datei is null) return null;
@@ -1,7 +1,7 @@
using Halo.Metadata;
using Flaro.Metadata;
using Microsoft.AspNetCore.Mvc;
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
public static class ImageEndpoints
{
@@ -1,7 +1,7 @@
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
public static class LibraryContentEndpoints
{
@@ -26,7 +26,7 @@ public static class LibraryContentEndpoints
/// Je Datei einzeln zu fragen hiesse: fünfzig Titel, fünfzig Abfragen —
/// und SQLite führt die nacheinander aus.
/// </remarks>
private static async Task<ILookup<Guid, MediaStreamResponse>> SpurenZu(HaloContext db, List<Guid> dateien)
private static async Task<ILookup<Guid, MediaStreamResponse>> SpurenZu(FlaroContext db, List<Guid> dateien)
{
if (dateien.Count == 0) return Array.Empty<(Guid, MediaStreamResponse)>().ToLookup(x => x.Item1, x => x.Item2);
@@ -48,7 +48,7 @@ public static class LibraryContentEndpoints
private static void MapScan(IEndpointRouteBuilder app)
{
app.MapPost("/api/v1/libraries/{id:guid}/scan", async (
Guid id, HaloContext db, ScanCoordinator koordinator) =>
Guid id, FlaroContext db, ScanCoordinator koordinator) =>
{
if (!await db.Libraries.AnyAsync(l => l.Id == id)) return Results.NotFound();
@@ -57,7 +57,7 @@ public static class LibraryContentEndpoints
: Results.Problem(
"Für diese Bibliothek läuft bereits ein Scan.",
statusCode: StatusCodes.Status409Conflict);
}).RequireAuthorization(HaloPolicies.Administrator);
}).RequireAuthorization(FlaroPolicies.Administrator);
app.MapGet("/api/v1/libraries/{id:guid}/scan", (Guid id, ScanCoordinator koordinator) =>
{
@@ -82,7 +82,7 @@ public static class LibraryContentEndpoints
private static void MapBrowse(IEndpointRouteBuilder app)
{
app.MapGet("/api/v1/movies", async (
HaloContext db, Guid? library, string? search, int skip = 0, int take = 50) =>
FlaroContext db, Guid? library, string? search, int skip = 0, int take = 50) =>
{
var abfrage = db.Movies.AsNoTracking();
if (library is { } kennung) abfrage = abfrage.Where(m => m.LibraryId == kennung);
@@ -115,7 +115,7 @@ public static class LibraryContentEndpoints
}).RequireAuthorization();
app.MapGet("/api/v1/series", async (
HaloContext db, Guid? library, string? search, int skip = 0, int take = 50) =>
FlaroContext db, Guid? library, string? search, int skip = 0, int take = 50) =>
{
var abfrage = db.Series.AsNoTracking();
if (library is { } kennung) abfrage = abfrage.Where(s => s.LibraryId == kennung);
@@ -146,7 +146,7 @@ public static class LibraryContentEndpoints
return Results.Ok(new Page<SeriesResponse>(items, gesamt));
}).RequireAuthorization();
app.MapGet("/api/v1/series/{id:guid}/episodes", async (Guid id, HaloContext db, int? season) =>
app.MapGet("/api/v1/series/{id:guid}/episodes", async (Guid id, FlaroContext db, int? season) =>
{
if (!await db.Series.AnyAsync(s => s.Id == id)) return Results.NotFound();
@@ -1,24 +1,24 @@
using Halo.Api.Auth;
using Halo.Core.Libraries;
using Halo.Core.Users;
using Halo.Data;
using Flaro.Api.Auth;
using Flaro.Core.Libraries;
using Flaro.Core.Users;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
public static class ManagementEndpoints
{
public static void MapManagement(this IEndpointRouteBuilder app)
{
var benutzer = app.MapGroup("/api/v1/users").RequireAuthorization(HaloPolicies.Administrator);
var benutzer = app.MapGroup("/api/v1/users").RequireAuthorization(FlaroPolicies.Administrator);
benutzer.MapGet("/", async (HaloContext db) =>
benutzer.MapGet("/", async (FlaroContext db) =>
Results.Ok(await db.Users
.OrderBy(u => u.UserName)
.Select(u => new AuthenticatedUser(u.Id, u.UserName, u.IsAdministrator))
.ToListAsync()));
benutzer.MapPost("/", async (CreateUserRequest anfrage, HaloContext db) =>
benutzer.MapPost("/", async (CreateUserRequest anfrage, FlaroContext db) =>
{
var name = anfrage.UserName.Trim();
if (name.Length == 0 || anfrage.Password.Length < 8)
@@ -45,14 +45,14 @@ public static class ManagementEndpoints
var bibliotheken = app.MapGroup("/api/v1/libraries");
// Lesen darf jeder Angemeldete — ohne die Liste zeigt die App nichts an.
bibliotheken.MapGet("/", async (HaloContext db) =>
bibliotheken.MapGet("/", async (FlaroContext db) =>
Results.Ok(await db.Libraries
.OrderBy(l => l.Name)
.Select(l => new LibraryResponse(l.Id, l.Name, l.Kind.ToString(), l.Path))
.ToListAsync()))
.RequireAuthorization();
bibliotheken.MapPost("/", async (CreateLibraryRequest anfrage, HaloContext db) =>
bibliotheken.MapPost("/", async (CreateLibraryRequest anfrage, FlaroContext db) =>
{
if (!Enum.TryParse<LibraryKind>(anfrage.Kind, ignoreCase: true, out var art))
return Results.ValidationProblem(new Dictionary<string, string[]>
@@ -75,16 +75,16 @@ public static class ManagementEndpoints
await db.SaveChangesAsync();
return Results.Created($"/api/v1/libraries/{neu.Id}",
new LibraryResponse(neu.Id, neu.Name, neu.Kind.ToString(), neu.Path));
}).RequireAuthorization(HaloPolicies.Administrator);
}).RequireAuthorization(FlaroPolicies.Administrator);
}
}
public static class HaloPolicies
public static class FlaroPolicies
{
public const string Administrator = "administrator-only";
}
public static class HaloRateLimits
public static class FlaroRateLimits
{
/// <summary>Für alles, was ein Geheimnis prüft.</summary>
public const string SignIn = "sign-in";
@@ -1,9 +1,9 @@
using Halo.Core.Library;
using Halo.Core.Metadata;
using Halo.Data;
using Flaro.Core.Library;
using Flaro.Core.Metadata;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
/// <summary>Eine falsche Zuordnung von Hand richtigstellen.</summary>
///
@@ -26,7 +26,7 @@ public static class MatchEndpoints
public static void MapMatching(this IEndpointRouteBuilder app)
{
app.MapGet("/api/v1/movies/{id:guid}/matches", async (
Guid id, HaloContext db, IMetadataProvider anbieter, string? query, int? year) =>
Guid id, FlaroContext db, IMetadataProvider anbieter, string? query, int? year) =>
{
var film = await db.Movies.AsNoTracking().FirstOrDefaultAsync(m => m.Id == id);
if (film is null) return Results.NotFound();
@@ -38,10 +38,10 @@ public static class MatchEndpoints
return Results.Ok(vorschläge.Select(v =>
new MatchCandidate(v.ProviderId, v.Title, v.Year, v.Overview, v.Poster?.Url)).ToList());
}).RequireAuthorization(HaloPolicies.Administrator);
}).RequireAuthorization(FlaroPolicies.Administrator);
app.MapPut("/api/v1/movies/{id:guid}/match", async (
Guid id, ApplyMatchRequest anfrage, HaloContext db,
Guid id, ApplyMatchRequest anfrage, FlaroContext db,
IMetadataProvider anbieter, MatchApplier anwender) =>
{
var film = await db.Movies.FirstOrDefaultAsync(m => m.Id == id);
@@ -54,10 +54,10 @@ public static class MatchEndpoints
await anwender.ApplyAsync(film, gefunden);
return Results.Ok(new MatchState(film.TmdbId, film.ImdbId, film.MatchLocked, film.Title, film.Year));
}).RequireAuthorization(HaloPolicies.Administrator);
}).RequireAuthorization(FlaroPolicies.Administrator);
app.MapGet("/api/v1/series/{id:guid}/matches", async (
Guid id, HaloContext db, IMetadataProvider anbieter, string? query, int? year) =>
Guid id, FlaroContext db, IMetadataProvider anbieter, string? query, int? year) =>
{
var serie = await db.Series.AsNoTracking().FirstOrDefaultAsync(s => s.Id == id);
if (serie is null) return Results.NotFound();
@@ -67,10 +67,10 @@ public static class MatchEndpoints
return Results.Ok(vorschläge.Select(v =>
new MatchCandidate(v.ProviderId, v.Title, v.Year, v.Overview, v.Poster?.Url)).ToList());
}).RequireAuthorization(HaloPolicies.Administrator);
}).RequireAuthorization(FlaroPolicies.Administrator);
app.MapPut("/api/v1/series/{id:guid}/match", async (
Guid id, ApplyMatchRequest anfrage, HaloContext db,
Guid id, ApplyMatchRequest anfrage, FlaroContext db,
IMetadataProvider anbieter, MatchApplier anwender) =>
{
var serie = await db.Series.FirstOrDefaultAsync(s => s.Id == id);
@@ -83,6 +83,6 @@ public static class MatchEndpoints
await anwender.ApplyAsync(serie, gefunden);
return Results.Ok(new MatchState(serie.TmdbId, serie.ImdbId, serie.MatchLocked, serie.Title, serie.Year));
}).RequireAuthorization(HaloPolicies.Administrator);
}).RequireAuthorization(FlaroPolicies.Administrator);
}
}
@@ -1,15 +1,15 @@
using Halo.Core;
using Halo.Data;
using Halo.Metadata;
using Flaro.Core;
using Flaro.Data;
using Flaro.Metadata;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
public static class SettingsEndpoints
{
public static void MapSettings(this IEndpointRouteBuilder app)
{
app.MapGet("/api/v1/settings/metadata", async (HaloContext db) =>
app.MapGet("/api/v1/settings/metadata", async (FlaroContext db) =>
{
var zeilen = await db.Settings.AsNoTracking()
.Where(s => s.Key == DatabaseTmdbSettings.ApiKeyName || s.Key == DatabaseTmdbSettings.LanguageName)
@@ -28,10 +28,10 @@ public static class SettingsEndpoints
// Damit in der Oberfläche steht, ob der mitgelieferte Schlüssel
// benutzt wird — und dass ein eigener ihn ablösen würde.
UsingProjectKey: aufgelöst.UsingProjectKey));
}).RequireAuthorization(HaloPolicies.Administrator);
}).RequireAuthorization(FlaroPolicies.Administrator);
app.MapPut("/api/v1/settings/metadata", async (
MetadataSettingsRequest anfrage, HaloContext db) =>
MetadataSettingsRequest anfrage, FlaroContext db) =>
{
if (anfrage.ApiKey is not null) await Setzen(db, DatabaseTmdbSettings.ApiKeyName, anfrage.ApiKey.Trim());
if (anfrage.Language is not null)
@@ -49,10 +49,10 @@ public static class SettingsEndpoints
await db.SaveChangesAsync();
return Results.NoContent();
}).RequireAuthorization(HaloPolicies.Administrator);
}).RequireAuthorization(FlaroPolicies.Administrator);
}
private static async Task Setzen(HaloContext db, string schlüssel, string wert)
private static async Task Setzen(FlaroContext db, string schlüssel, string wert)
{
var vorhanden = await db.Settings.FindAsync(schlüssel);
if (vorhanden is null) db.Settings.Add(new ServerSetting { Key = schlüssel, Value = wert });
@@ -1,9 +1,9 @@
using Halo.Core.Users;
using Halo.Metadata;
using Halo.Data;
using Flaro.Core.Users;
using Flaro.Metadata;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api.Endpoints;
namespace Flaro.Api.Endpoints;
public static class SystemEndpoints
{
@@ -18,7 +18,7 @@ public static class SystemEndpoints
public static void MapSystem(this IEndpointRouteBuilder app)
{
app.MapGet("/api/v1/system/info", async (HaloContext db) =>
app.MapGet("/api/v1/system/info", async (FlaroContext db) =>
Results.Ok(new SystemInfo(
Version: typeof(SystemEndpoints).Assembly.GetName().Version?.ToString(3) ?? "0.0.0",
NeedsSetup: !await db.Users.AnyAsync(),
@@ -30,7 +30,7 @@ public static class SystemEndpoints
])))
.AllowAnonymous();
app.MapPost("/api/v1/system/setup", async (SetupRequest anfrage, HaloContext db) =>
app.MapPost("/api/v1/system/setup", async (SetupRequest anfrage, FlaroContext db) =>
{
if (string.IsNullOrWhiteSpace(anfrage.UserName) || anfrage.Password.Length < 8)
return Results.ValidationProblem(new Dictionary<string, string[]>
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<ProjectReference Include="..\Halo.Core\Halo.Core.csproj" />
<ProjectReference Include="..\Halo.Data\Halo.Data.csproj" />
<ProjectReference Include="..\Halo.Metadata\Halo.Metadata.csproj" />
<ProjectReference Include="..\Halo.Media\Halo.Media.csproj" />
<ProjectReference Include="..\Flaro.Core\Flaro.Core.csproj" />
<ProjectReference Include="..\Flaro.Data\Flaro.Data.csproj" />
<ProjectReference Include="..\Flaro.Metadata\Flaro.Metadata.csproj" />
<ProjectReference Include="..\Flaro.Media\Flaro.Media.csproj" />
</ItemGroup>
<ItemGroup>
@@ -1,4 +1,4 @@
namespace Halo.Api;
namespace Flaro.Api;
/// <summary>Wo der Server seine Sachen ablegt.</summary>
///
@@ -21,26 +21,26 @@ namespace Halo.Api;
/// Container neu starten, um eine Bibliothek hinzuzufügen.
/// </para>
/// </remarks>
public sealed class HaloPaths
public sealed class FlaroPaths
{
public required string Data { get; init; }
public required string Cache { get; init; }
public required string Transcode { get; init; }
public string DatabaseFile => Path.Combine(Data, "halo.db");
public string DatabaseFile => Path.Combine(Data, "flaro.db");
public static HaloPaths FromEnvironment(string contentRoot)
public static FlaroPaths FromEnvironment(string contentRoot)
{
string lies(string name, string voreinstellung) =>
Environment.GetEnvironmentVariable(name) is { Length: > 0 } wert
? wert
: Path.Combine(contentRoot, voreinstellung);
return new HaloPaths
return new FlaroPaths
{
Data = lies("HALO_DATA", "data"),
Cache = lies("HALO_CACHE", "cache"),
Transcode = lies("HALO_TRANSCODE", "transcode"),
Data = lies("FLARO_DATA", "data"),
Cache = lies("FLARO_CACHE", "cache"),
Transcode = lies("FLARO_TRANSCODE", "transcode"),
};
}
@@ -62,13 +62,13 @@ public sealed class HaloPaths
/// </remarks>
public void EnsureExists()
{
foreach (var (name, pfad) in new[] { ("HALO_DATA", Data), ("HALO_CACHE", Cache), ("HALO_TRANSCODE", Transcode) })
foreach (var (name, pfad) in new[] { ("FLARO_DATA", Data), ("FLARO_CACHE", Cache), ("FLARO_TRANSCODE", Transcode) })
{
try
{
Directory.CreateDirectory(pfad);
var probe = Path.Combine(pfad, $".halo-schreibprobe-{Environment.ProcessId}");
var probe = Path.Combine(pfad, $".flaro-schreibprobe-{Environment.ProcessId}");
File.WriteAllBytes(probe, []);
File.Delete(probe);
}
@@ -78,7 +78,7 @@ public sealed class HaloPaths
$"""
{name} zeigt auf „{pfad}“, und dort lässt sich nicht schreiben.
Halo läuft als Benutzer {Kennung()}. Dieses Verzeichnis muss
Flaro läuft als Benutzer {Kennung()}. Dieses Verzeichnis muss
ihm gehören oder für ihn beschreibbar sein.
Im Container ist das fast immer die Einhängung: entweder gehört
@@ -1,9 +1,9 @@
using Halo.Core.Library;
using Halo.Core.Metadata;
using Halo.Data;
using Flaro.Core.Library;
using Flaro.Core.Metadata;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api;
namespace Flaro.Api;
/// <summary>Schreibt eine korrigierte Zuordnung überallhin, wo sie hingehört.</summary>
///
@@ -14,7 +14,7 @@ namespace Halo.Api;
/// Entscheidung wieder überstimmt.
/// </remarks>
public sealed class MatchApplier(
HaloContext db,
FlaroContext db,
IMetadataProvider anbieter,
IImageStore bilder,
IImageReader bildLeser,
@@ -1,20 +1,20 @@
using Halo.Data;
using Halo.Metadata;
using Flaro.Data;
using Flaro.Metadata;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api;
namespace Flaro.Api;
/// <summary>Holt die Metadaten-Einstellungen aus der Datenbank.</summary>
///
/// <remarks>
/// <b>Hier und nicht in <c>Halo.Data</c>:</b> sonst müsste die Datenschicht
/// <b>Hier und nicht in <c>Flaro.Data</c>:</b> sonst müsste die Datenschicht
/// den Metadaten-Anbieter kennen. So zeigen beide Richtungen auf den Kern und
/// keine aufeinander.
///
/// Je Anfrage einmal gelesen und dann gemerkt. Ohne das fragte ein Scan über
/// tausend Titel tausendmal dieselbe Zeile ab.
/// </remarks>
public sealed class DatabaseTmdbSettings(HaloContext db) : ITmdbSettingsSource
public sealed class DatabaseTmdbSettings(FlaroContext db) : ITmdbSettingsSource
{
public const string ApiKeyName = "metadata.tmdb.apiKey";
public const string LanguageName = "metadata.language";
@@ -1,11 +1,11 @@
using System.Collections.Concurrent;
using Halo.Core.Delivery;
using Halo.Core.Library;
using Halo.Data;
using Halo.Media;
using Flaro.Core.Delivery;
using Flaro.Core.Library;
using Flaro.Data;
using Flaro.Media;
using Microsoft.EntityFrameworkCore;
namespace Halo.Api;
namespace Flaro.Api;
public sealed record PackageState(
string Status,
@@ -27,12 +27,12 @@ public sealed record PackageState(
/// </para>
/// <para>
/// Der Preis ist Plattenplatz und Wartezeit vor dem ersten Byte. Dafür gibt
/// es <c>HALO_TRANSCODE</c>, und dafür meldet dieser Weg einen Fortschritt.
/// es <c>FLARO_TRANSCODE</c>, und dafür meldet dieser Weg einen Fortschritt.
/// </para>
/// </remarks>
public sealed class PackageCoordinator(
IServiceScopeFactory scopes,
HaloPaths pfade,
FlaroPaths pfade,
TimeProvider clock,
ILogger<PackageCoordinator> log)
{
@@ -77,7 +77,7 @@ public sealed class PackageCoordinator(
try
{
using var bereich = scopes.CreateScope();
var db = bereich.ServiceProvider.GetRequiredService<HaloContext>();
var db = bereich.ServiceProvider.GetRequiredService<FlaroContext>();
var datei = await db.MediaFiles.AsNoTracking().FirstOrDefaultAsync(f => f.Id == fileId)
?? throw new InvalidOperationException("Diese Datei steht nicht mehr in der Mediathek.");
@@ -1,24 +1,24 @@
using System.Threading.RateLimiting;
using Halo.Api;
using Halo.Api.Auth;
using Halo.Api.Endpoints;
using Halo.Core.Metadata;
using Halo.Data;
using Halo.Core.Library;
using Halo.Media;
using Halo.Metadata;
using Flaro.Api;
using Flaro.Api.Auth;
using Flaro.Api.Endpoints;
using Flaro.Core.Metadata;
using Flaro.Data;
using Flaro.Core.Library;
using Flaro.Media;
using Flaro.Metadata;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
var pfade = HaloPaths.FromEnvironment(builder.Environment.ContentRootPath);
var pfade = FlaroPaths.FromEnvironment(builder.Environment.ContentRootPath);
pfade.EnsureExists();
builder.Services.AddSingleton(pfade);
builder.Services.AddSingleton(TimeProvider.System);
builder.Services.AddDbContext<HaloContext>(o => o.UseSqlite($"Data Source={pfade.DatabaseFile}"));
builder.Services.AddDbContext<FlaroContext>(o => o.UseSqlite($"Data Source={pfade.DatabaseFile}"));
builder.Services
.AddAuthentication(TokenAuthenticationHandler.SchemeName)
@@ -31,9 +31,9 @@ builder.Services.AddAuthorizationBuilder()
// dem irgendwann einer vergessen wird.
.SetFallbackPolicy(new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder()
.RequireAuthenticatedUser().Build())
.AddPolicy(HaloPolicies.Administrator, p => p.RequireRole(HaloRoles.Administrator));
.AddPolicy(FlaroPolicies.Administrator, p => p.RequireRole(FlaroRoles.Administrator));
// Einstellbar, weil die richtige Zahl vom Aufbau abhängt: steht Halo hinter
// Einstellbar, weil die richtige Zahl vom Aufbau abhängt: steht Flaro hinter
// einem Reverse Proxy, erscheinen **alle** Benutzer unter derselben Adresse
// und teilen sich einen Eimer. Wer das nicht weiss, hält die eigene App für
// kaputt, während in Wahrheit der Nachbar im selben Haus gerade angemeldet hat.
@@ -47,16 +47,16 @@ int grenze(string name, int voreinstellung) =>
builder.Services.AddRateLimiter(o =>
{
o.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
var beimAnmelden = grenze("HALO_RATELIMIT_SIGNIN", 10);
var beimNachfragen = grenze("HALO_RATELIMIT_POLLING", 120);
var beimAnmelden = grenze("FLARO_RATELIMIT_SIGNIN", 10);
var beimNachfragen = grenze("FLARO_RATELIMIT_POLLING", 120);
// Je Absender, nicht global: sonst sperrt ein einzelner Angreifer den
// ganzen Haushalt aus, und die Abwehr wäre selbst der Ausfall.
o.AddPolicy(HaloRateLimits.SignIn, anfrage => RateLimitPartition.GetFixedWindowLimiter(
o.AddPolicy(FlaroRateLimits.SignIn, anfrage => RateLimitPartition.GetFixedWindowLimiter(
anfrage.Connection.RemoteIpAddress?.ToString() ?? "unbekannt",
_ => new FixedWindowRateLimiterOptions { PermitLimit = beimAnmelden, Window = TimeSpan.FromMinutes(1) }));
o.AddPolicy(HaloRateLimits.Polling, anfrage => RateLimitPartition.GetFixedWindowLimiter(
o.AddPolicy(FlaroRateLimits.Polling, anfrage => RateLimitPartition.GetFixedWindowLimiter(
anfrage.Connection.RemoteIpAddress?.ToString() ?? "unbekannt",
_ => new FixedWindowRateLimiterOptions { PermitLimit = beimNachfragen, Window = TimeSpan.FromMinutes(1) }));
});
@@ -100,7 +100,7 @@ var app = builder.Build();
// hochfährt, soll nicht erst eine Migration von Hand anstossen müssen.
using (var bereich = app.Services.CreateScope())
{
await bereich.ServiceProvider.GetRequiredService<HaloContext>().Database.MigrateAsync();
await bereich.ServiceProvider.GetRequiredService<FlaroContext>().Database.MigrateAsync();
}
app.UseExceptionHandler();
@@ -1,7 +1,7 @@
using System.Collections.Concurrent;
using Halo.Data;
using Flaro.Data;
namespace Halo.Api;
namespace Flaro.Api;
public sealed record ScanState(
string Status,
@@ -1,6 +1,6 @@
using System.Security.Cryptography;
namespace Halo.Core.Auth;
namespace Flaro.Core.Auth;
/// <summary>Eine laufende Anmeldung per Code — für den Fernseher.</summary>
///
@@ -1,4 +1,4 @@
namespace Halo.Core.Auth;
namespace Flaro.Core.Auth;
/// <summary>Ein angemeldetes Gerät.</summary>
///
@@ -1,7 +1,7 @@
using System.Security.Cryptography;
using System.Text;
namespace Halo.Core.Auth;
namespace Flaro.Core.Auth;
/// <summary>Erzeugt und verfingert Geheimnisse, die Clients vorzeigen.</summary>
///
@@ -1,6 +1,6 @@
using Halo.Core.Library;
using Flaro.Core.Library;
namespace Halo.Core.Delivery;
namespace Flaro.Core.Delivery;
public enum DeliveryMethod
{
@@ -1,4 +1,4 @@
namespace Halo.Core.Delivery;
namespace Flaro.Core.Delivery;
/// <summary>Was ein Gerät von sich aus öffnen kann.</summary>
///
@@ -1,4 +1,4 @@
namespace Halo.Core.Libraries;
namespace Flaro.Core.Libraries;
public enum LibraryKind { Movies, Shows }
@@ -7,7 +7,7 @@ public enum LibraryKind { Movies, Shows }
/// <remarks>
/// <b>In der Datenbank und nicht in der Umgebung.</b> Stünden Medienpfade in
/// der Compose-Datei, müsste der Container neu starten, um eine Bibliothek
/// hinzuzufügen — und ein Fremder, der Halo zum ersten Mal startet, hätte
/// hinzuzufügen — und ein Fremder, der Flaro zum ersten Mal startet, hätte
/// keine Datei, in der schon das Richtige steht.
/// </remarks>
public sealed class Library
@@ -1,7 +1,7 @@
using System.Globalization;
using System.Text.RegularExpressions;
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
public sealed record MovieName(string Title, int? Year);
@@ -1,4 +1,4 @@
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
/// <summary>Was in einer Datei steckt.</summary>
public sealed record ProbeResult(
@@ -1,4 +1,4 @@
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
/// <summary>Legt Beiwerk neben eine Mediendatei.</summary>
///
@@ -1,4 +1,4 @@
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
/// <summary>Eine gefundene Datei, so wie das Dateisystem sie beschreibt.</summary>
public sealed record ScannedFile(string Path, long SizeBytes, DateTimeOffset ModifiedAt);
@@ -1,4 +1,4 @@
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
/// <summary>Eine Datei auf der Platte, so wie der Scan sie vorgefunden hat.</summary>
///
@@ -1,4 +1,4 @@
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
/// <summary>Welche Dateien überhaupt als Medien gelten.</summary>
///
@@ -1,4 +1,4 @@
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
public enum MediaStreamKind { Video, Audio, Subtitle }
@@ -1,7 +1,7 @@
using System.Xml;
using System.Xml.Linq;
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
public sealed record MovieNfo(
string Title, int? Year, string? Plot, ProviderIds Ids, bool Locked);
@@ -132,7 +132,7 @@ public static class Nfo
///
/// <remarks>
/// <b>DTDs sind abgeschaltet und es wird nichts nachgeladen.</b> Diese
/// Dateien liegen im Medienordner, und was dort liegt, hat Halo nicht
/// Dateien liegen im Medienordner, und was dort liegt, hat Flaro nicht
/// geschrieben — eine NFO mit einer externen Entität könnte sonst den
/// Server dazu bringen, fremde Dateien zu lesen und auszuliefern.
/// </remarks>
@@ -1,6 +1,6 @@
using System.Text.RegularExpressions;
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
/// <summary>Kennungen bei Metadatenquellen, wie sie in Namen stehen können.</summary>
public sealed record ProviderIds(int? Tmdb, string? Imdb)
@@ -16,10 +16,10 @@ public sealed record ProviderIds(int? Tmdb, string? Imdb)
/// <b>Die Form stammt von Kodi und wird von Jellyfin gelesen:</b>
/// <c>Der Untergang (2004) [tmdbid-613]</c>. Wer seine Ordner so benennt —
/// von Hand oder über Radarr —, hat seine Zuordnung damit festgeschrieben,
/// und Halo soll sie nicht erneut erraten.
/// und Flaro soll sie nicht erneut erraten.
/// </para>
/// <para>
/// <b>Halo benennt nichts um.</b> Es liest nur. Festgeschrieben wird eine
/// <b>Flaro benennt nichts um.</b> Es liest nur. Festgeschrieben wird eine
/// Korrektur in der NFO-Datei — dieselbe Wirkung, ohne den einen Eingriff,
/// der eine Bibliothek wirklich zerlegen kann.
/// </para>
@@ -1,6 +1,6 @@
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
/// <summary>Welche Dateien Halo neben eine Mediendatei legen darf — und sonst keine.</summary>
/// <summary>Welche Dateien Flaro neben eine Mediendatei legen darf — und sonst keine.</summary>
///
/// <remarks>
/// <para>
@@ -17,7 +17,7 @@ namespace Halo.Core.Library;
/// </para>
/// <para>
/// <b>Transcode-Zwischenstände gehören ausdrücklich nicht hierher.</b> Die
/// liegen unter <c>HALO_TRANSCODE</c>, auf einem eigenen Volume. Ein
/// liegen unter <c>FLARO_TRANSCODE</c>, auf einem eigenen Volume. Ein
/// Medienordner ist kein Kratzplatz.
/// </para>
/// </remarks>
@@ -1,4 +1,4 @@
namespace Halo.Core.Library;
namespace Flaro.Core.Library;
/// <summary>Der Titel, nach dem sortiert wird — ohne den Artikel davor.</summary>
///
@@ -1,4 +1,4 @@
namespace Halo.Core.Metadata;
namespace Flaro.Core.Metadata;
/// <summary>Ein Bild bei der Quelle — noch nicht heruntergeladen.</summary>
public sealed record RemoteImage(string Url);
@@ -1,4 +1,4 @@
namespace Halo.Core;
namespace Flaro.Core;
/// <summary>Eine Einstellung des Servers, als Zeile in der Datenbank.</summary>
///
@@ -2,7 +2,7 @@ using System.Security.Cryptography;
using System.Text;
using Konscious.Security.Cryptography;
namespace Halo.Core.Users;
namespace Flaro.Core.Users;
/// <summary>Passwörter als Argon2id, im PHC-Format abgelegt.</summary>
///
@@ -1,4 +1,4 @@
namespace Halo.Core.Users;
namespace Flaro.Core.Users;
/// <summary>Ein Benutzerkonto.</summary>
///
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Halo.Data;
namespace Flaro.Data;
/// <summary>Zeitpunkte als Unix-Millisekunden statt als Text.</summary>
///
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Halo.Core\Halo.Core.csproj" />
<ProjectReference Include="..\Flaro.Core\Flaro.Core.csproj" />
</ItemGroup>
<ItemGroup>
@@ -1,11 +1,11 @@
using Halo.Core;
using Halo.Core.Auth;
using Halo.Core.Libraries;
using Halo.Core.Library;
using Halo.Core.Users;
using Flaro.Core;
using Flaro.Core.Auth;
using Flaro.Core.Libraries;
using Flaro.Core.Library;
using Flaro.Core.Users;
using Microsoft.EntityFrameworkCore;
namespace Halo.Data;
namespace Flaro.Data;
/// <summary>Die Datenbank des Servers.</summary>
///
@@ -19,7 +19,7 @@ namespace Halo.Data;
/// nicht — dann ist der Umstieg auf PostgreSQL fällig, und deshalb steht hier
/// nirgends SQLite-eigenes SQL.
/// </remarks>
public sealed class HaloContext(DbContextOptions<HaloContext> options) : DbContext(options)
public sealed class FlaroContext(DbContextOptions<FlaroContext> options) : DbContext(options)
{
public DbSet<User> Users => Set<User>();
public DbSet<DeviceToken> DeviceTokens => Set<DeviceToken>();
@@ -1,9 +1,9 @@
using Halo.Core.Libraries;
using Halo.Core.Library;
using Flaro.Core.Libraries;
using Flaro.Core.Library;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace Halo.Data;
namespace Flaro.Data;
public sealed record ScanReport(
int FilesFound,
@@ -31,7 +31,7 @@ public sealed record ScanReport(
/// </para>
/// </remarks>
public sealed class LibraryScanner(
HaloContext db, IMediaProbe sonde, TimeProvider clock, ILogger<LibraryScanner> log)
FlaroContext db, IMediaProbe sonde, TimeProvider clock, ILogger<LibraryScanner> log)
{
public async Task<ScanReport> ScanAsync(Guid libraryId, CancellationToken ct = default)
{
@@ -1,9 +1,9 @@
using Halo.Core.Library;
using Halo.Core.Metadata;
using Flaro.Core.Library;
using Flaro.Core.Metadata;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace Halo.Data;
namespace Flaro.Data;
public sealed record EnrichReport(
int MoviesMatched, int SeriesMatched, int EpisodesMatched, bool Skipped, string? Error);
@@ -25,7 +25,7 @@ public sealed record EnrichReport(
/// </para>
/// </remarks>
public sealed class MetadataEnricher(
HaloContext db,
FlaroContext db,
IMetadataProvider anbieter,
IImageStore bilder,
IImageReader bildLeser,
@@ -1,6 +1,6 @@
// <auto-generated />
using System;
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
[DbContext(typeof(HaloContext))]
[DbContext(typeof(FlaroContext))]
[Migration("20261003095500_Initial")]
partial class Initial
{
@@ -20,7 +20,7 @@ namespace Halo.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");
modelBuilder.Entity("Halo.Core.Auth.AuthCode", b =>
modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -68,7 +68,7 @@ namespace Halo.Data.Migrations
b.ToTable("AuthCodes");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -111,7 +111,7 @@ namespace Halo.Data.Migrations
b.ToTable("DeviceTokens");
});
modelBuilder.Entity("Halo.Core.Libraries.Library", b =>
modelBuilder.Entity("Flaro.Core.Libraries.Library", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -140,7 +140,7 @@ namespace Halo.Data.Migrations
b.ToTable("Libraries");
});
modelBuilder.Entity("Halo.Core.ServerSetting", b =>
modelBuilder.Entity("Flaro.Core.ServerSetting", b =>
{
b.Property<string>("Key")
.HasMaxLength(128)
@@ -156,7 +156,7 @@ namespace Halo.Data.Migrations
b.ToTable("Settings");
});
modelBuilder.Entity("Halo.Core.Users.User", b =>
modelBuilder.Entity("Flaro.Core.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -187,9 +187,9 @@ namespace Halo.Data.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.HasOne("Halo.Core.Users.User", null)
b.HasOne("Flaro.Core.Users.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
@@ -1,6 +1,6 @@
// <auto-generated />
using System;
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
[DbContext(typeof(HaloContext))]
[DbContext(typeof(FlaroContext))]
[Migration("20261003115256_Mediathek")]
partial class Mediathek
{
@@ -20,7 +20,7 @@ namespace Halo.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");
modelBuilder.Entity("Halo.Core.Auth.AuthCode", b =>
modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -68,7 +68,7 @@ namespace Halo.Data.Migrations
b.ToTable("AuthCodes");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -111,7 +111,7 @@ namespace Halo.Data.Migrations
b.ToTable("DeviceTokens");
});
modelBuilder.Entity("Halo.Core.Libraries.Library", b =>
modelBuilder.Entity("Flaro.Core.Libraries.Library", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -140,7 +140,7 @@ namespace Halo.Data.Migrations
b.ToTable("Libraries");
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -173,7 +173,7 @@ namespace Halo.Data.Migrations
b.ToTable("Episodes");
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -214,7 +214,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaFiles");
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -252,7 +252,7 @@ namespace Halo.Data.Migrations
b.ToTable("Movies");
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -290,7 +290,7 @@ namespace Halo.Data.Migrations
b.ToTable("Series");
});
modelBuilder.Entity("Halo.Core.ServerSetting", b =>
modelBuilder.Entity("Flaro.Core.ServerSetting", b =>
{
b.Property<string>("Key")
.HasMaxLength(128)
@@ -306,7 +306,7 @@ namespace Halo.Data.Migrations
b.ToTable("Settings");
});
modelBuilder.Entity("Halo.Core.Users.User", b =>
modelBuilder.Entity("Flaro.Core.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -337,45 +337,45 @@ namespace Halo.Data.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.HasOne("Halo.Core.Users.User", null)
b.HasOne("Flaro.Core.Users.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.HasOne("Halo.Core.Library.Series", null)
b.HasOne("Flaro.Core.Library.Series", null)
.WithMany()
.HasForeignKey("SeriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
@@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
/// <inheritdoc />
public partial class Mediathek : Migration
@@ -1,6 +1,6 @@
// <auto-generated />
using System;
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
[DbContext(typeof(HaloContext))]
[DbContext(typeof(FlaroContext))]
[Migration("20261003120100_Metadaten")]
partial class Metadaten
{
@@ -20,7 +20,7 @@ namespace Halo.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");
modelBuilder.Entity("Halo.Core.Auth.AuthCode", b =>
modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -68,7 +68,7 @@ namespace Halo.Data.Migrations
b.ToTable("AuthCodes");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -111,7 +111,7 @@ namespace Halo.Data.Migrations
b.ToTable("DeviceTokens");
});
modelBuilder.Entity("Halo.Core.Libraries.Library", b =>
modelBuilder.Entity("Flaro.Core.Libraries.Library", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -140,7 +140,7 @@ namespace Halo.Data.Migrations
b.ToTable("Libraries");
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -176,7 +176,7 @@ namespace Halo.Data.Migrations
b.ToTable("Episodes");
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -217,7 +217,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaFiles");
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -261,7 +261,7 @@ namespace Halo.Data.Migrations
b.ToTable("Movies");
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -305,7 +305,7 @@ namespace Halo.Data.Migrations
b.ToTable("Series");
});
modelBuilder.Entity("Halo.Core.ServerSetting", b =>
modelBuilder.Entity("Flaro.Core.ServerSetting", b =>
{
b.Property<string>("Key")
.HasMaxLength(128)
@@ -321,7 +321,7 @@ namespace Halo.Data.Migrations
b.ToTable("Settings");
});
modelBuilder.Entity("Halo.Core.Users.User", b =>
modelBuilder.Entity("Flaro.Core.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -352,45 +352,45 @@ namespace Halo.Data.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.HasOne("Halo.Core.Users.User", null)
b.HasOne("Flaro.Core.Users.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.HasOne("Halo.Core.Library.Series", null)
b.HasOne("Flaro.Core.Library.Series", null)
.WithMany()
.HasForeignKey("SeriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
@@ -2,7 +2,7 @@
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
/// <inheritdoc />
public partial class Metadaten : Migration
@@ -1,6 +1,6 @@
// <auto-generated />
using System;
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
[DbContext(typeof(HaloContext))]
[DbContext(typeof(FlaroContext))]
[Migration("20261003123234_GeparsterTitel")]
partial class GeparsterTitel
{
@@ -20,7 +20,7 @@ namespace Halo.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");
modelBuilder.Entity("Halo.Core.Auth.AuthCode", b =>
modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -68,7 +68,7 @@ namespace Halo.Data.Migrations
b.ToTable("AuthCodes");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -111,7 +111,7 @@ namespace Halo.Data.Migrations
b.ToTable("DeviceTokens");
});
modelBuilder.Entity("Halo.Core.Libraries.Library", b =>
modelBuilder.Entity("Flaro.Core.Libraries.Library", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -140,7 +140,7 @@ namespace Halo.Data.Migrations
b.ToTable("Libraries");
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -176,7 +176,7 @@ namespace Halo.Data.Migrations
b.ToTable("Episodes");
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -217,7 +217,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaFiles");
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -265,7 +265,7 @@ namespace Halo.Data.Migrations
b.ToTable("Movies");
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -313,7 +313,7 @@ namespace Halo.Data.Migrations
b.ToTable("Series");
});
modelBuilder.Entity("Halo.Core.ServerSetting", b =>
modelBuilder.Entity("Flaro.Core.ServerSetting", b =>
{
b.Property<string>("Key")
.HasMaxLength(128)
@@ -329,7 +329,7 @@ namespace Halo.Data.Migrations
b.ToTable("Settings");
});
modelBuilder.Entity("Halo.Core.Users.User", b =>
modelBuilder.Entity("Flaro.Core.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -360,45 +360,45 @@ namespace Halo.Data.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.HasOne("Halo.Core.Users.User", null)
b.HasOne("Flaro.Core.Users.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.HasOne("Halo.Core.Library.Series", null)
b.HasOne("Flaro.Core.Library.Series", null)
.WithMany()
.HasForeignKey("SeriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
@@ -2,7 +2,7 @@
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
/// <inheritdoc />
public partial class GeparsterTitel : Migration
@@ -1,6 +1,6 @@
// <auto-generated />
using System;
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
[DbContext(typeof(HaloContext))]
[DbContext(typeof(FlaroContext))]
[Migration("20261003150124_Spuren")]
partial class Spuren
{
@@ -20,7 +20,7 @@ namespace Halo.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");
modelBuilder.Entity("Halo.Core.Auth.AuthCode", b =>
modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -68,7 +68,7 @@ namespace Halo.Data.Migrations
b.ToTable("AuthCodes");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -111,7 +111,7 @@ namespace Halo.Data.Migrations
b.ToTable("DeviceTokens");
});
modelBuilder.Entity("Halo.Core.Libraries.Library", b =>
modelBuilder.Entity("Flaro.Core.Libraries.Library", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -140,7 +140,7 @@ namespace Halo.Data.Migrations
b.ToTable("Libraries");
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -176,7 +176,7 @@ namespace Halo.Data.Migrations
b.ToTable("Episodes");
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -230,7 +230,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaFiles");
});
modelBuilder.Entity("Halo.Core.Library.MediaStream", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaStream", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -282,7 +282,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaStreams");
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -330,7 +330,7 @@ namespace Halo.Data.Migrations
b.ToTable("Movies");
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -378,7 +378,7 @@ namespace Halo.Data.Migrations
b.ToTable("Series");
});
modelBuilder.Entity("Halo.Core.ServerSetting", b =>
modelBuilder.Entity("Flaro.Core.ServerSetting", b =>
{
b.Property<string>("Key")
.HasMaxLength(128)
@@ -394,7 +394,7 @@ namespace Halo.Data.Migrations
b.ToTable("Settings");
});
modelBuilder.Entity("Halo.Core.Users.User", b =>
modelBuilder.Entity("Flaro.Core.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -425,54 +425,54 @@ namespace Halo.Data.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.HasOne("Halo.Core.Users.User", null)
b.HasOne("Flaro.Core.Users.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.HasOne("Halo.Core.Library.Series", null)
b.HasOne("Flaro.Core.Library.Series", null)
.WithMany()
.HasForeignKey("SeriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaStream", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaStream", b =>
{
b.HasOne("Halo.Core.Library.MediaFile", null)
b.HasOne("Flaro.Core.Library.MediaFile", null)
.WithMany()
.HasForeignKey("MediaFileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
@@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
/// <inheritdoc />
public partial class Spuren : Migration
@@ -1,6 +1,6 @@
// <auto-generated />
using System;
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
[DbContext(typeof(HaloContext))]
[DbContext(typeof(FlaroContext))]
[Migration("20261003165210_Zuordnung")]
partial class Zuordnung
{
@@ -20,7 +20,7 @@ namespace Halo.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");
modelBuilder.Entity("Halo.Core.Auth.AuthCode", b =>
modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -68,7 +68,7 @@ namespace Halo.Data.Migrations
b.ToTable("AuthCodes");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -111,7 +111,7 @@ namespace Halo.Data.Migrations
b.ToTable("DeviceTokens");
});
modelBuilder.Entity("Halo.Core.Libraries.Library", b =>
modelBuilder.Entity("Flaro.Core.Libraries.Library", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -140,7 +140,7 @@ namespace Halo.Data.Migrations
b.ToTable("Libraries");
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -176,7 +176,7 @@ namespace Halo.Data.Migrations
b.ToTable("Episodes");
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -230,7 +230,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaFiles");
});
modelBuilder.Entity("Halo.Core.Library.MediaStream", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaStream", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -282,7 +282,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaStreams");
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -337,7 +337,7 @@ namespace Halo.Data.Migrations
b.ToTable("Movies");
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -392,7 +392,7 @@ namespace Halo.Data.Migrations
b.ToTable("Series");
});
modelBuilder.Entity("Halo.Core.ServerSetting", b =>
modelBuilder.Entity("Flaro.Core.ServerSetting", b =>
{
b.Property<string>("Key")
.HasMaxLength(128)
@@ -408,7 +408,7 @@ namespace Halo.Data.Migrations
b.ToTable("Settings");
});
modelBuilder.Entity("Halo.Core.Users.User", b =>
modelBuilder.Entity("Flaro.Core.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -439,54 +439,54 @@ namespace Halo.Data.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.HasOne("Halo.Core.Users.User", null)
b.HasOne("Flaro.Core.Users.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.HasOne("Halo.Core.Library.Series", null)
b.HasOne("Flaro.Core.Library.Series", null)
.WithMany()
.HasForeignKey("SeriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaStream", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaStream", b =>
{
b.HasOne("Halo.Core.Library.MediaFile", null)
b.HasOne("Flaro.Core.Library.MediaFile", null)
.WithMany()
.HasForeignKey("MediaFileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
@@ -2,7 +2,7 @@
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
/// <inheritdoc />
public partial class Zuordnung : Migration
@@ -1,6 +1,6 @@
// <auto-generated />
using System;
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
[DbContext(typeof(HaloContext))]
[DbContext(typeof(FlaroContext))]
[Migration("20261003165918_GeparstesJahr")]
partial class GeparstesJahr
{
@@ -20,7 +20,7 @@ namespace Halo.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");
modelBuilder.Entity("Halo.Core.Auth.AuthCode", b =>
modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -68,7 +68,7 @@ namespace Halo.Data.Migrations
b.ToTable("AuthCodes");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -111,7 +111,7 @@ namespace Halo.Data.Migrations
b.ToTable("DeviceTokens");
});
modelBuilder.Entity("Halo.Core.Libraries.Library", b =>
modelBuilder.Entity("Flaro.Core.Libraries.Library", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -140,7 +140,7 @@ namespace Halo.Data.Migrations
b.ToTable("Libraries");
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -176,7 +176,7 @@ namespace Halo.Data.Migrations
b.ToTable("Episodes");
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -230,7 +230,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaFiles");
});
modelBuilder.Entity("Halo.Core.Library.MediaStream", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaStream", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -282,7 +282,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaStreams");
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -340,7 +340,7 @@ namespace Halo.Data.Migrations
b.ToTable("Movies");
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -398,7 +398,7 @@ namespace Halo.Data.Migrations
b.ToTable("Series");
});
modelBuilder.Entity("Halo.Core.ServerSetting", b =>
modelBuilder.Entity("Flaro.Core.ServerSetting", b =>
{
b.Property<string>("Key")
.HasMaxLength(128)
@@ -414,7 +414,7 @@ namespace Halo.Data.Migrations
b.ToTable("Settings");
});
modelBuilder.Entity("Halo.Core.Users.User", b =>
modelBuilder.Entity("Flaro.Core.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -445,54 +445,54 @@ namespace Halo.Data.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.HasOne("Halo.Core.Users.User", null)
b.HasOne("Flaro.Core.Users.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.HasOne("Halo.Core.Library.Series", null)
b.HasOne("Flaro.Core.Library.Series", null)
.WithMany()
.HasForeignKey("SeriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaStream", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaStream", b =>
{
b.HasOne("Halo.Core.Library.MediaFile", null)
b.HasOne("Flaro.Core.Library.MediaFile", null)
.WithMany()
.HasForeignKey("MediaFileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
@@ -2,7 +2,7 @@
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
/// <inheritdoc />
public partial class GeparstesJahr : Migration
@@ -1,23 +1,23 @@
// <auto-generated />
using System;
using Halo.Data;
using Flaro.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Halo.Data.Migrations
namespace Flaro.Data.Migrations
{
[DbContext(typeof(HaloContext))]
partial class HaloContextModelSnapshot : ModelSnapshot
[DbContext(typeof(FlaroContext))]
partial class FlaroContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");
modelBuilder.Entity("Halo.Core.Auth.AuthCode", b =>
modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -65,7 +65,7 @@ namespace Halo.Data.Migrations
b.ToTable("AuthCodes");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -108,7 +108,7 @@ namespace Halo.Data.Migrations
b.ToTable("DeviceTokens");
});
modelBuilder.Entity("Halo.Core.Libraries.Library", b =>
modelBuilder.Entity("Flaro.Core.Libraries.Library", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -137,7 +137,7 @@ namespace Halo.Data.Migrations
b.ToTable("Libraries");
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -173,7 +173,7 @@ namespace Halo.Data.Migrations
b.ToTable("Episodes");
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -227,7 +227,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaFiles");
});
modelBuilder.Entity("Halo.Core.Library.MediaStream", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaStream", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -279,7 +279,7 @@ namespace Halo.Data.Migrations
b.ToTable("MediaStreams");
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -337,7 +337,7 @@ namespace Halo.Data.Migrations
b.ToTable("Movies");
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -395,7 +395,7 @@ namespace Halo.Data.Migrations
b.ToTable("Series");
});
modelBuilder.Entity("Halo.Core.ServerSetting", b =>
modelBuilder.Entity("Flaro.Core.ServerSetting", b =>
{
b.Property<string>("Key")
.HasMaxLength(128)
@@ -411,7 +411,7 @@ namespace Halo.Data.Migrations
b.ToTable("Settings");
});
modelBuilder.Entity("Halo.Core.Users.User", b =>
modelBuilder.Entity("Flaro.Core.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -442,54 +442,54 @@ namespace Halo.Data.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b =>
modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b =>
{
b.HasOne("Halo.Core.Users.User", null)
b.HasOne("Flaro.Core.Users.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Episode", b =>
modelBuilder.Entity("Flaro.Core.Library.Episode", b =>
{
b.HasOne("Halo.Core.Library.Series", null)
b.HasOne("Flaro.Core.Library.Series", null)
.WithMany()
.HasForeignKey("SeriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaFile", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaFile", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.MediaStream", b =>
modelBuilder.Entity("Flaro.Core.Library.MediaStream", b =>
{
b.HasOne("Halo.Core.Library.MediaFile", null)
b.HasOne("Flaro.Core.Library.MediaFile", null)
.WithMany()
.HasForeignKey("MediaFileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Movie", b =>
modelBuilder.Entity("Flaro.Core.Library.Movie", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Halo.Core.Library.Series", b =>
modelBuilder.Entity("Flaro.Core.Library.Series", b =>
{
b.HasOne("Halo.Core.Libraries.Library", null)
b.HasOne("Flaro.Core.Libraries.Library", null)
.WithMany()
.HasForeignKey("LibraryId")
.OnDelete(DeleteBehavior.Cascade)
@@ -1,4 +1,4 @@
namespace Halo.Media;
namespace Flaro.Media;
/// <summary>Wo ffmpeg liegt und wie lange es brauchen darf.</summary>
///
@@ -20,6 +20,6 @@ public sealed record FfmpegOptions(string Ffmpeg = "ffmpeg", string Ffprobe = "f
public TimeSpan ProbeTimeout { get; init; } = TimeSpan.FromSeconds(30);
public static FfmpegOptions FromEnvironment() => new(
Environment.GetEnvironmentVariable("HALO_FFMPEG") is { Length: > 0 } f ? f : "ffmpeg",
Environment.GetEnvironmentVariable("HALO_FFPROBE") is { Length: > 0 } p ? p : "ffprobe");
Environment.GetEnvironmentVariable("FLARO_FFMPEG") is { Length: > 0 } f ? f : "ffmpeg",
Environment.GetEnvironmentVariable("FLARO_FFPROBE") is { Length: > 0 } p ? p : "ffprobe");
}
@@ -2,7 +2,7 @@ using System.Diagnostics;
using System.Globalization;
using Microsoft.Extensions.Logging;
namespace Halo.Media;
namespace Flaro.Media;
public sealed record RemuxOutcome(bool Success, string? Error);
@@ -1,10 +1,10 @@
using System.Diagnostics;
using System.Globalization;
using System.Text.Json;
using Halo.Core.Library;
using Flaro.Core.Library;
using Microsoft.Extensions.Logging;
namespace Halo.Media;
namespace Flaro.Media;
/// <summary>Liest die technischen Angaben einer Datei mit ffprobe.</summary>
///
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Halo.Core\Halo.Core.csproj" />
<ProjectReference Include="..\Flaro.Core\Flaro.Core.csproj" />
</ItemGroup>
<ItemGroup>
@@ -1,7 +1,7 @@
using Halo.Core.Delivery;
using Halo.Core.Library;
using Flaro.Core.Delivery;
using Flaro.Core.Library;
namespace Halo.Media;
namespace Flaro.Media;
public sealed record RemuxRequest(
string SourcePath,
@@ -1,20 +1,20 @@
using Halo.Core.Library;
using Flaro.Core.Library;
using Microsoft.Extensions.Logging;
namespace Halo.Media;
namespace Flaro.Media;
/// <summary>Ob Halo überhaupt in Medienordner schreiben darf.</summary>
/// <summary>Ob Flaro überhaupt in Medienordner schreiben darf.</summary>
///
/// <remarks>
/// <b>Standardmässig aus.</b> In fremde Medienordner zu schreiben ist nichts,
/// was ein Server ungefragt tun sollte — und für viele Aufbauten ist die
/// Einhängung ohnehin schreibgeschützt. Wer es will, setzt
/// <c>HALO_WRITE_SIDECARS=true</c> und hängt die Medien ohne <c>:ro</c> ein.
/// <c>FLARO_WRITE_SIDECARS=true</c> und hängt die Medien ohne <c>:ro</c> ein.
/// </remarks>
public sealed record SidecarOptions(bool Enabled)
{
public static SidecarOptions FromEnvironment() => new(
Environment.GetEnvironmentVariable("HALO_WRITE_SIDECARS")?.Trim()
Environment.GetEnvironmentVariable("FLARO_WRITE_SIDECARS")?.Trim()
.Equals("true", StringComparison.OrdinalIgnoreCase) == true);
}
@@ -52,7 +52,7 @@ public sealed class SidecarWriter(SidecarOptions optionen, ILogger<SidecarWriter
{
// **Gelesen wird auch, wenn nicht geschrieben werden darf.** Eine
// vorhandene NFO ist eine Zuordnung, die jemand getroffen hat — die
// zu übergehen, bloss weil Halo selbst nicht schreiben soll, wäre
// zu übergehen, bloss weil Flaro selbst nicht schreiben soll, wäre
// verkehrt herum.
Pruefen(beiwerkName);
var pfad = Pfad(mediendatei, beiwerkName);
@@ -92,7 +92,7 @@ public sealed class SidecarWriter(SidecarOptions optionen, ILogger<SidecarWriter
if (!optionen.Enabled) return;
var ziel = Pfad(mediendatei, beiwerkName);
var halbfertig = ziel + ".halo-tmp";
var halbfertig = ziel + ".flaro-tmp";
try
{
@@ -117,7 +117,7 @@ public sealed class SidecarWriter(SidecarOptions optionen, ILogger<SidecarWriter
if (SidecarNames.MayWrite(beiwerkName)) return;
throw new InvalidOperationException(
$"„{beiwerkName}“ steht nicht auf der Liste der Dateien, die Halo anlegen darf. " +
$"„{beiwerkName}“ steht nicht auf der Liste der Dateien, die Flaro anlegen darf. " +
"Siehe SidecarNames — das ist der Schutz des Bestands, und er wird nicht umgangen.");
}
}
@@ -1,4 +1,4 @@
namespace Halo.Metadata;
namespace Flaro.Metadata;
/// <summary>Was TMDB verlangt, wenn man ihre Daten benutzt.</summary>
///
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Halo.Core\Halo.Core.csproj" />
<ProjectReference Include="..\Flaro.Core\Flaro.Core.csproj" />
</ItemGroup>
<ItemGroup>
@@ -1,9 +1,9 @@
using System.Security.Cryptography;
using System.Text;
using Halo.Core.Metadata;
using Flaro.Core.Metadata;
using Microsoft.Extensions.Logging;
namespace Halo.Metadata;
namespace Flaro.Metadata;
public sealed record ImageCacheOptions(string Root);
@@ -80,7 +80,7 @@ public sealed class ImageCache(
///
/// <remarks>
/// <b>Die Prüfung ist kein Schmuck.</b> Der Schlüssel kommt aus einer
/// Adresszeile. Ohne sie wäre <c>/api/v1/images/..%2f..%2fconfig%2fhalo.db</c>
/// Adresszeile. Ohne sie wäre <c>/api/v1/images/..%2f..%2fconfig%2fflaro.db</c>
/// ein Weg, die Datenbank herunterzuladen — samt aller Token-Fingerabdrücke.
/// </remarks>
public string? PfadFür(string schlüssel)
@@ -1,10 +1,10 @@
using System.Net;
using System.Text.Json;
using System.Text.Json.Serialization;
using Halo.Core.Metadata;
using Flaro.Core.Metadata;
using Microsoft.Extensions.Logging;
namespace Halo.Metadata;
namespace Flaro.Metadata;
/// <summary>Fragt TMDB nach Titeln, Beschreibungen und Bildern.</summary>
///
@@ -1,9 +1,9 @@
namespace Halo.Metadata;
namespace Flaro.Metadata;
/// <summary>Was TMDB braucht, um zu antworten.</summary>
public sealed record TmdbSettings(string? ApiKey, string Language, bool UsingProjectKey = false)
{
/// <summary>Englisch als Voreinstellung, weil Halo nicht nur hier läuft.</summary>
/// <summary>Englisch als Voreinstellung, weil Flaro nicht nur hier läuft.</summary>
///
/// <remarks>
/// Der Betreiber stellt in der Oberfläche um. Eine deutsche Voreinstellung
@@ -16,8 +16,8 @@ public sealed record TmdbSettings(string? ApiKey, string Language, bool UsingPro
///
/// <remarks>
/// <para>
/// <b>Hier gehört der Schlüssel hinein, den Halo ausliefert.</b> Ist er
/// leer, verlangt Halo von jedem Betreiber einen eigenen — die Mediathek
/// <b>Hier gehört der Schlüssel hinein, den Flaro ausliefert.</b> Ist er
/// leer, verlangt Flaro von jedem Betreiber einen eigenen — die Mediathek
/// läuft dann trotzdem, nur mit Dateinamen statt Titeln.
/// </para>
/// <para>