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:
co-authored by
Claude Opus 5
parent
f98b995050
commit
a7cf6c5def
@@ -0,0 +1,133 @@
|
||||
using Flaro.Core.Delivery;
|
||||
using Flaro.Core.Library;
|
||||
|
||||
namespace Flaro.Core.Tests;
|
||||
|
||||
public class DeliveryDeciderTests
|
||||
{
|
||||
private static ProbedStream Bild(string codec = "h264") =>
|
||||
new(0, MediaStreamKind.Video, codec, null, null, true, false, null, 1920, 1080);
|
||||
|
||||
private static ProbedStream Ton(int index, string codec = "aac", string? sprache = "deu", string? name = null) =>
|
||||
new(index, MediaStreamKind.Audio, codec, sprache, name, index == 1, false, 6, null, null);
|
||||
|
||||
private static ProbedStream Text(int index, string codec = "subrip") =>
|
||||
new(index, MediaStreamKind.Subtitle, codec, "deu", null, false, false, null, null, null);
|
||||
|
||||
[Test]
|
||||
public void Eine_passende_MP4_geht_unveraendert_hinaus()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload("mp4", [Bild(), Ton(1)]);
|
||||
|
||||
Assert.That(plan.Method, Is.EqualTo(DeliveryMethod.DirectFile));
|
||||
Assert.That(plan.NeedsWork, Is.False);
|
||||
Assert.That(plan.Reasons, Is.EqualTo(new[] { DeliveryReason.NativelySupported }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Eine_Matroska_muss_umgepackt_werden_auch_wenn_alles_darin_passt()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload("mkv", [Bild(), Ton(1)]);
|
||||
|
||||
Assert.That(plan.Method, Is.EqualTo(DeliveryMethod.Remux));
|
||||
Assert.That(plan.Reasons, Does.Contain(DeliveryReason.ContainerUnsupported));
|
||||
// Das Bild bleibt unberührt, und kein Ton muss gerechnet werden.
|
||||
Assert.That(plan.AudioToEncode, Is.Empty);
|
||||
}
|
||||
|
||||
/// <summary>Der Fall, um den es im ganzen Projekt geht.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Zwei Tonspuren, und beide kommen mit.</b> Der Plan hat gar kein Feld
|
||||
/// „welche Tonspur" — und das ist der Unterschied zu Jellyfin, dessen
|
||||
/// Transcode-Endpunkt je Sitzung genau eine abbildet. Wer hier eine
|
||||
/// auswählen wollte, fände keine Stelle dafür.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void Alle_Tonspuren_bleiben_erhalten()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload("mkv",
|
||||
[Bild(), Ton(1, name: "Deutsch"), Ton(2, name: "Audiodeskription"), Ton(3, sprache: "eng")]);
|
||||
|
||||
Assert.That(plan.Method, Is.EqualTo(DeliveryMethod.Remux));
|
||||
Assert.That(plan.AudioToEncode, Is.Empty, "Alle drei passen und werden nur umgepackt");
|
||||
Assert.That(plan.SubtitlesDropped, Is.Empty);
|
||||
}
|
||||
|
||||
/// <summary>DTS kennt AVPlayer nicht — nur diese eine Spur wird gerechnet.</summary>
|
||||
[Test]
|
||||
public void Nur_untaugliche_Tonspuren_werden_neu_gerechnet()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload("mkv", [Bild(), Ton(1, "aac"), Ton(2, "dts"), Ton(3, "truehd")]);
|
||||
|
||||
Assert.That(plan.AudioToEncode, Is.EqualTo(new[] { 2, 3 }));
|
||||
Assert.That(plan.Reasons, Does.Contain(DeliveryReason.AudioCodecUnsupported));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Textuntertitel_werden_fuer_MP4_umgeschrieben()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload("mkv", [Bild(), Ton(1), Text(2, "subrip")]);
|
||||
|
||||
Assert.That(plan.Reasons, Does.Contain(DeliveryReason.SubtitlesNeedConversion));
|
||||
Assert.That(plan.SubtitlesDropped, Is.Empty);
|
||||
}
|
||||
|
||||
/// <summary>Betrifft fast jeden Blu-ray-Rip.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// PGS liegt als Bild vor, und in eine MP4 passt das nicht. Diese Spuren
|
||||
/// fallen weg — und das muss gesagt werden, statt stillschweigend zu
|
||||
/// geschehen: sonst sucht jemand nach Untertiteln, die der Server bewusst
|
||||
/// weggelassen hat.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void Bilduntertitel_fallen_weg_und_das_steht_im_Plan()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload("mkv",
|
||||
[Bild(), Ton(1), Text(2, "hdmv_pgs_subtitle"), Text(3, "subrip")]);
|
||||
|
||||
Assert.That(plan.SubtitlesDropped, Is.EqualTo(new[] { 2 }));
|
||||
Assert.That(plan.Reasons, Does.Contain(DeliveryReason.ImageSubtitlesDropped));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ein_untaugliches_Bild_verlangt_ebenfalls_Umpacken()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload("mkv", [Bild("vp9"), Ton(1)]);
|
||||
Assert.That(plan.Reasons, Does.Contain(DeliveryReason.VideoCodecUnsupported));
|
||||
}
|
||||
|
||||
/// <summary>Was die Datei nicht nennt, gilt als passend.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Vorsichtshalber umzupacken hiesse, aus einer tadellosen MP4 eine neue
|
||||
/// Datei zu machen — für eine Angabe, die schlicht fehlt.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void Fehlende_Angaben_loesen_kein_Umpacken_aus()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload(null,
|
||||
[Bild(null!) with { Codec = null }, Ton(1) with { Codec = null }]);
|
||||
|
||||
Assert.That(plan.Method, Is.EqualTo(DeliveryMethod.DirectFile));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Jeder_Grund_steht_nur_einmal_da()
|
||||
{
|
||||
var plan = DeliveryDecider.ForDownload("mkv", [Bild(), Ton(1, "dts"), Ton(2, "truehd"), Ton(3, "vorbis")]);
|
||||
|
||||
Assert.That(plan.Reasons.Count(g => g == DeliveryReason.AudioCodecUnsupported), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ein_eigenes_Geraeteprofil_sticht_die_Voreinstellung()
|
||||
{
|
||||
var alleskoenner = new DeviceProfile(
|
||||
new HashSet<string> { "mkv" }, new HashSet<string> { "h264" }, new HashSet<string> { "dts" });
|
||||
|
||||
var plan = DeliveryDecider.ForDownload("mkv", [Bild(), Ton(1, "dts")], alleskoenner);
|
||||
Assert.That(plan.Method, Is.EqualTo(DeliveryMethod.DirectFile));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user