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,89 @@
|
||||
namespace Flaro.Core.Library;
|
||||
|
||||
/// <summary>Welche Dateien Flaro neben eine Mediendatei legen darf — und sonst keine.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Eine Erlaubnisliste, und sie ist der ganze Schutz.</b> Damit Plakate und
|
||||
/// Metadaten im Filmordner landen können, muss die Einhängung schreibbar
|
||||
/// sein — und damit kann der Server im Grundsatz alles dort anstellen. Dass
|
||||
/// er es nicht tut, hängt an dieser Liste und an der Prüfung darunter.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Mediendateien werden nie angefasst.</b> Nicht geändert, nicht
|
||||
/// umbenannt, nicht gelöscht. Es gibt im ganzen Projekt keine Stelle, die das
|
||||
/// könnte, und diese Liste ist der Grund: was nicht daraufsteht, wird
|
||||
/// abgelehnt — auch wenn jemand es ausdrücklich verlangt.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Transcode-Zwischenstände gehören ausdrücklich nicht hierher.</b> Die
|
||||
/// liegen unter <c>FLARO_TRANSCODE</c>, auf einem eigenen Volume. Ein
|
||||
/// Medienordner ist kein Kratzplatz.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class SidecarNames
|
||||
{
|
||||
public const string MoviePoster = "poster.jpg";
|
||||
public const string MovieBackdrop = "fanart.jpg";
|
||||
public const string MovieLogo = "logo.png";
|
||||
public const string MovieNfo = "movie.nfo";
|
||||
|
||||
public const string SeriesPoster = "poster.jpg";
|
||||
public const string SeriesBackdrop = "fanart.jpg";
|
||||
public const string SeriesNfo = "tvshow.nfo";
|
||||
|
||||
/// <summary>Was zu einer Folge gehört, hängt am Namen ihrer Datei.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Aus <c>Dark - S01E01.mkv</c> werden <c>Dark - S01E01.nfo</c> und
|
||||
/// <c>Dark - S01E01-thumb.jpg</c>. So erwarten es Kodi, Jellyfin und Plex
|
||||
/// — und so findet auch ein Mensch sie wieder.
|
||||
/// </remarks>
|
||||
public static string EpisodeNfo(string mediendatei) =>
|
||||
Path.GetFileNameWithoutExtension(mediendatei) + ".nfo";
|
||||
|
||||
public static string EpisodeThumb(string mediendatei) =>
|
||||
Path.GetFileNameWithoutExtension(mediendatei) + "-thumb.jpg";
|
||||
|
||||
/// <summary>Beiwerk für einen Film, der sich den Ordner mit anderen teilt.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Sonst überschreiben sich zwei Filme gegenseitig das Plakat.</b> Wer
|
||||
/// je Film einen Ordner anlegt, bekommt die schlichten Namen; wer zehn
|
||||
/// Filme nebeneinanderlegt, bekommt sie mit dem Dateinamen davor. Kodi und
|
||||
/// Jellyfin lesen beide Formen.
|
||||
/// </remarks>
|
||||
public static string Prefixed(string mediendatei, string beiwerk) =>
|
||||
Path.GetFileNameWithoutExtension(mediendatei) + "-" + beiwerk;
|
||||
|
||||
private static readonly HashSet<string> Feste = new(StringComparer.OrdinalIgnoreCase)
|
||||
{ MoviePoster, MovieBackdrop, MovieLogo, MovieNfo, SeriesNfo };
|
||||
|
||||
private static readonly string[] Endungen =
|
||||
[".nfo", "-thumb.jpg", "-poster.jpg", "-fanart.jpg", "-logo.png"];
|
||||
|
||||
/// <summary>Ob dieser Dateiname geschrieben werden darf.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Geprüft wird der Name, nicht die Absicht.</b> Ein Pfadbestandteil,
|
||||
/// ein Verzeichniswechsel oder ein führender Punkt kommen hier nicht
|
||||
/// durch — und „film.mkv" erst recht nicht, auch wenn es auf <c>.nfo</c>
|
||||
/// endete.
|
||||
/// </remarks>
|
||||
public static bool MayWrite(string dateiname)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(dateiname)) return false;
|
||||
|
||||
// Kein Pfad, nur ein Name. Alles andere könnte aus dem Ordner führen.
|
||||
if (dateiname.Contains('/') || dateiname.Contains('\\')) return false;
|
||||
if (dateiname != Path.GetFileName(dateiname)) return false;
|
||||
if (dateiname.StartsWith('.')) return false;
|
||||
if (dateiname.Contains("..", StringComparison.Ordinal)) return false;
|
||||
|
||||
if (Feste.Contains(dateiname)) return true;
|
||||
|
||||
// Je Folge: beliebiger Rumpf, aber nur mit diesen Endungen.
|
||||
return Endungen.Any(e => dateiname.EndsWith(e, StringComparison.OrdinalIgnoreCase)
|
||||
&& dateiname.Length > e.Length);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user