4K, Full HD, HD, SD — die Zahl steht beim Überfahren
„1080p" ist eine Angabe für den, der eine Stufe einstellt. Wer sich fragt,
ob es sich lohnt, dafür den Fernseher anzumachen, liest „Full HD". Die
Zeile sagt jetzt das Wort, der Tooltip den genauen Wert und die gemessene
Grösse: `1080p · 1920 × 800`.
**Es gab zwei Leitern, und sie waren sich uneinig.** `Benennung.AusHoehe`
machte aus 2160 ein „2160p", `FileNames.FassungAusHoehe` ein „4K" — auf
derselben Detailseite stand beides übereinander, ein paar Zeilen
auseinander. Die zweite ist weg; sie hatte ausserdem nur die Höhe und
vergab sich damit beim Kinoformat.
Gemessen an zwei echten Dateien: 1920×800 heisst „Full HD" (nur an der
Höhe gemessen hiesse es „HD", und daneben stünde ein 1280×720 mit
demselben Wort), 720×576 heisst „SD".
**1440p fällt unter Full HD.** „QHD" kennt kaum jemand, und ein fünftes
Wort für etwas zwischen zwei bekannten hilft beim Entscheiden nicht.
„8K" steht nur da, damit eine 8K-Datei nicht als 4K gemeldet wird.
**Der Client zerlegt nichts mehr.** Er las die Stufe bisher mit
`display.split(' · ')[0]` heraus — richtig, solange vor der Auflösung nie
etwas anderes steht. Jetzt kommen Wort und genauer Wert als eigene Felder.
**Die Fassung wird nicht mehr gespeichert, sondern gerechnet.** Sie stand
in der Spalte und war damit das, was beim letzten Scan galt: ein neues
Wort hätte keine bestehende Zeile erreicht. Jetzt hält die Spalte nur
noch, was im Dateinamen stand („Mobil"), und die Messung kommt frisch
dazu. Eine Migration räumt die alten gerechneten Werte weg.
**Nicht angefasst:** was eine *gewählte* Stufe ist statt einer gemessenen
— die Umkodierleiter, der Qualitätswähler im Spieler, die Stufen in den
Apps. Wer eine Stufe wählt, wählt eine Zahl.
Die Apps rechnen sich das Wort ohnehin selbst aus und sagen seit jeher
„4K" und „Full HD"; der Server ist ihnen jetzt angeglichen, nicht
umgekehrt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
168fcdfb4c
commit
c65356c16f
@@ -278,6 +278,17 @@ public sealed record MediaStreamResponse(
|
|||||||
/// stehen weiterhin daneben; wer sie braucht, hat sie.
|
/// stehen weiterhin daneben; wer sie braucht, hat sie.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
string? Display = null,
|
string? Display = null,
|
||||||
|
/// <summary>Die Auflösung als Wort — „4K", „Full HD", „HD", „SD".</summary>
|
||||||
|
///
|
||||||
|
/// <remarks>
|
||||||
|
/// <b>Eigenes Feld, damit der Client nichts zerlegen muss.</b> Die
|
||||||
|
/// Oberfläche las die Stufe bisher mit <c>display.split(' · ')[0]</c>
|
||||||
|
/// heraus — richtig, solange vor der Auflösung nie etwas anderes steht,
|
||||||
|
/// und falsch an dem Tag, an dem doch.
|
||||||
|
/// </remarks>
|
||||||
|
string? ResolutionLabel = null,
|
||||||
|
/// <summary>Dieselbe Auflösung genau — „1080p". Gehört in den Tooltip.</summary>
|
||||||
|
string? ResolutionExact = null,
|
||||||
|
|
||||||
/// <summary>Die Sprache als Wort — „Deutsch" statt „deu".</summary>
|
/// <summary>Die Sprache als Wort — „Deutsch" statt „deu".</summary>
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -95,7 +95,11 @@ public static class LibraryContentEndpoints
|
|||||||
MediaStreamKind.Audio => Benennung.Tonspur(s.Language, s.Codec, s.Channels, s.Title),
|
MediaStreamKind.Audio => Benennung.Tonspur(s.Language, s.Codec, s.Channels, s.Title),
|
||||||
_ => Benennung.Untertitelspur(s.Language, s.IsForced, fuerHoergeschaedigte: false),
|
_ => Benennung.Untertitelspur(s.Language, s.IsForced, fuerHoergeschaedigte: false),
|
||||||
},
|
},
|
||||||
LanguageName: Benennung.Sprache(s.Language)));
|
LanguageName: Benennung.Sprache(s.Language),
|
||||||
|
ResolutionLabel: s.Kind == MediaStreamKind.Video
|
||||||
|
? Benennung.Aufloesungswort(s.Width, s.Height) : null,
|
||||||
|
ResolutionExact: s.Kind == MediaStreamKind.Video
|
||||||
|
? Benennung.Aufloesung(s.Width, s.Height) : null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaFileResponse Datei(
|
private static MediaFileResponse Datei(
|
||||||
@@ -104,12 +108,19 @@ public static class LibraryContentEndpoints
|
|||||||
string? mediathekspfad = null) =>
|
string? mediathekspfad = null) =>
|
||||||
new(id, System.IO.Path.GetFileName(pfad), bytes, schachtel, dauer?.TotalSeconds,
|
new(id, System.IO.Path.GetFileName(pfad), bytes, schachtel, dauer?.TotalSeconds,
|
||||||
spuren[id].ToList(),
|
spuren[id].ToList(),
|
||||||
// Steht sie nicht in der Datenbank, wird sie aus dem Pfad gelesen:
|
// **Drei Quellen, in dieser Reihenfolge.** Was in der Datenbank
|
||||||
// ein Bestand von vor dieser Änderung soll nicht erst neu gescannt
|
// steht, kam aus dem Dateinamen und ist das Genaueste. Sonst wird
|
||||||
// werden müssen, um „Mobil" zu zeigen.
|
// der Pfad gelesen — ein Bestand von vor dieser Änderung soll
|
||||||
fassung ?? FileNames.Fassung(pfad),
|
// nicht erst neu gescannt werden müssen, um „Mobil" zu zeigen.
|
||||||
|
// Und sonst die Messung: hier gerechnet und nicht gespeichert,
|
||||||
|
// damit ein neues Wort nicht erst einen Scan braucht.
|
||||||
|
fassung ?? FileNames.Fassung(pfad) ?? AusDenSpuren(spuren[id]),
|
||||||
Ordner(pfad, mediathekspfad));
|
Ordner(pfad, mediathekspfad));
|
||||||
|
|
||||||
|
/// <summary>Die Fassung aus der gemessenen Bildgrösse — „Full HD", „SD".</summary>
|
||||||
|
private static string? AusDenSpuren(IEnumerable<MediaStreamResponse> spuren) =>
|
||||||
|
spuren.FirstOrDefault(s => s.Kind == nameof(MediaStreamKind.Video))?.ResolutionLabel;
|
||||||
|
|
||||||
/// <summary>Der Pfad der Mediathek — nur für Administratoren.</summary>
|
/// <summary>Der Pfad der Mediathek — nur für Administratoren.</summary>
|
||||||
///
|
///
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
|||||||
@@ -166,24 +166,6 @@ public static partial class FileNames
|
|||||||
private static bool IstFassungsordner(string name) =>
|
private static bool IstFassungsordner(string name) =>
|
||||||
IstFassungsname(name) || Schlank(name).Equals("plexversions", StringComparison.OrdinalIgnoreCase);
|
IstFassungsname(name) || Schlank(name).Equals("plexversions", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
/// <summary>Macht aus einer gemessenen Höhe einen Namen: 2160 wird „4K".</summary>
|
|
||||||
///
|
|
||||||
/// <remarks>
|
|
||||||
/// Der Rückfall, wenn der Dateiname nichts hergibt. Zwei Dateien ohne
|
|
||||||
/// Zusatz hiessen sonst beide gleich, und in der Auswahl stünde zweimal
|
|
||||||
/// dasselbe.
|
|
||||||
/// </remarks>
|
|
||||||
public static string? FassungAusHoehe(int? hoehe) => hoehe switch
|
|
||||||
{
|
|
||||||
null or <= 0 => null,
|
|
||||||
>= 2000 => "4K",
|
|
||||||
>= 1400 => "1440p",
|
|
||||||
>= 1000 => "1080p",
|
|
||||||
>= 700 => "720p",
|
|
||||||
>= 500 => "576p",
|
|
||||||
_ => "SD",
|
|
||||||
};
|
|
||||||
|
|
||||||
private static bool IstFassungsname(string wort)
|
private static bool IstFassungsname(string wort)
|
||||||
{
|
{
|
||||||
var blank = wort.Trim();
|
var blank = wort.Trim();
|
||||||
@@ -207,7 +189,8 @@ public static partial class FileNames
|
|||||||
/// <b>Eine geschlossene Liste.</b> Nähme man jedes Wort hinter dem letzten
|
/// <b>Eine geschlossene Liste.</b> Nähme man jedes Wort hinter dem letzten
|
||||||
/// Bindestrich, hiesse eine Fassung irgendwann „YIFY" oder „GRP" — das
|
/// Bindestrich, hiesse eine Fassung irgendwann „YIFY" oder „GRP" — das
|
||||||
/// sind Veröffentlichungsgruppen, keine Fassungen. Lieber kein Name als
|
/// sind Veröffentlichungsgruppen, keine Fassungen. Lieber kein Name als
|
||||||
/// ein falscher: ohne Treffer greift <see cref="FassungAusHoehe"/>.
|
/// ein falscher: ohne Treffer rechnet die Antwort sie aus der gemessenen
|
||||||
|
/// Bildgrösse — <c>Benennung.Aufloesungswort</c>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private static readonly Dictionary<string, string> Fassungsnamen =
|
private static readonly Dictionary<string, string> Fassungsnamen =
|
||||||
new(StringComparer.OrdinalIgnoreCase)
|
new(StringComparer.OrdinalIgnoreCase)
|
||||||
|
|||||||
@@ -138,6 +138,42 @@ public static class Benennung
|
|||||||
_ => $"{hoehe}p",
|
_ => $"{hoehe}p",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>Dieselbe Messung als Wort: „4K", „Full HD", „HD", „SD".</summary>
|
||||||
|
///
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// <b>Wer schauen will, wählt keine Zeilenzahl.</b> „1080p" ist eine Angabe
|
||||||
|
/// für den, der eine Stufe einstellt; „Full HD" ist eine für den, der sich
|
||||||
|
/// fragt, ob es sich lohnt, dafür den Fernseher anzumachen. Der genaue Wert
|
||||||
|
/// geht nicht verloren — <see cref="Aufloesung(int?, int?)"/> liefert ihn
|
||||||
|
/// weiter, und die Oberfläche zeigt ihn beim Überfahren.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// <b>1440p heisst hier Full HD.</b> „QHD" kennt kaum jemand, und ein
|
||||||
|
/// fünftes Wort für eine Auflösung, die zwischen zwei bekannten liegt,
|
||||||
|
/// hilft niemandem beim Entscheiden. „8K" steht nur da, damit eine
|
||||||
|
/// 8K-Datei nicht als 4K gemeldet wird.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// <b>Gerechnet wird mit Breite und Höhe</b>, aus demselben Grund wie oben:
|
||||||
|
/// ein Film im Kinoformat hat 1920×800 und ist Full HD, nicht HD.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public static string? Aufloesungswort(int? breite, int? hoehe)
|
||||||
|
{
|
||||||
|
var a = Stufe(hoehe);
|
||||||
|
var b = Stufe(breite * 9 / 16);
|
||||||
|
return Math.Max(a ?? 0, b ?? 0) switch
|
||||||
|
{
|
||||||
|
<= 0 => null,
|
||||||
|
>= 3500 => "8K",
|
||||||
|
>= 2000 => "4K",
|
||||||
|
>= 1000 => "Full HD",
|
||||||
|
>= 700 => "HD",
|
||||||
|
_ => "SD",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Die ganze Zeile zu einer Tonspur.</summary>
|
/// <summary>Die ganze Zeile zu einer Tonspur.</summary>
|
||||||
public static string Tonspur(string? sprache, string? codec, int? kanaele, string? titel)
|
public static string Tonspur(string? sprache, string? codec, int? kanaele, string? titel)
|
||||||
{
|
{
|
||||||
@@ -177,7 +213,8 @@ public static class Benennung
|
|||||||
public static string Bildspur(string? codec, int? breite, int? hoehe)
|
public static string Bildspur(string? codec, int? breite, int? hoehe)
|
||||||
{
|
{
|
||||||
var teile = new List<string>();
|
var teile = new List<string>();
|
||||||
if (Aufloesung(breite, hoehe) is { } a) teile.Add(a);
|
// Das Wort, nicht die Zahl — siehe `Aufloesungswort`.
|
||||||
|
if (Aufloesungswort(breite, hoehe) is { } a) teile.Add(a);
|
||||||
if (Codec(codec) is { } c) teile.Add(c);
|
if (Codec(codec) is { } c) teile.Add(c);
|
||||||
return teile.Count > 0 ? string.Join(" · ", teile) : "Bild";
|
return teile.Count > 0 ? string.Join(" · ", teile) : "Bild";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -351,11 +351,12 @@ public sealed class LibraryScanner(
|
|||||||
datei.BitRate = gelesen.BitRate;
|
datei.BitRate = gelesen.BitRate;
|
||||||
datei.ProbedAt = laufZeit;
|
datei.ProbedAt = laufZeit;
|
||||||
|
|
||||||
// **Der Rückfall für den Fassungsnamen.** Steht im Dateinamen nichts,
|
// **Der Rückfall aus der Bildgrösse wird nicht mehr gespeichert.**
|
||||||
// taugt die gemessene Bildhöhe: zwei Dateien ohne Zusatz hiessen sonst
|
// Er stand in der Spalte und war damit das, was beim letzten Scan
|
||||||
// beide gleich, und in der Auswahl stünde zweimal dasselbe.
|
// gegolten hat: als aus „576p" ein „SD" wurde, blieb in jeder
|
||||||
datei.VersionLabel ??= FileNames.FassungAusHoehe(
|
// bestehenden Zeile das alte Wort stehen. Jetzt rechnet die Antwort
|
||||||
gelesen.Streams.FirstOrDefault(s => s.Kind == MediaStreamKind.Video)?.Height);
|
// ihn aus den Spuren — siehe `LibraryContentEndpoints.Datei`. In der
|
||||||
|
// Spalte steht nur noch, was im Dateinamen stand.
|
||||||
|
|
||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Flaro.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Fassungsnamen : Migration
|
||||||
|
{
|
||||||
|
/// <summary>Räumt die gespeicherten Fassungsnamen weg, die aus einer
|
||||||
|
/// Messung stammen.</summary>
|
||||||
|
///
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// <b>Kein Schemawechsel, ein Datenwechsel.</b> Der Fassungsname stand
|
||||||
|
/// bis jetzt in der Spalte, auch wenn er nur aus der Bildhöhe
|
||||||
|
/// gerechnet war — und damit stand dort, was beim letzten Scan galt.
|
||||||
|
/// Als aus „576p" ein „SD" wurde, erreichte das keine bestehende
|
||||||
|
/// Zeile.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Künftig rechnet die Antwort ihn aus den Spuren, und die Spalte hält
|
||||||
|
/// nur noch, was im Dateinamen stand. Diese Zeilen hier sind die
|
||||||
|
/// Altlast: alles, was wie eine gerechnete Fassung aussieht, wird
|
||||||
|
/// geleert. Ein „4K", das wirklich im Dateinamen stand, verschwindet
|
||||||
|
/// dabei auch — und kommt aus der Messung sofort als „4K" zurück.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
"""
|
||||||
|
UPDATE MediaFiles SET VersionLabel = NULL
|
||||||
|
WHERE VersionLabel GLOB '[0-9][0-9][0-9]p'
|
||||||
|
OR VersionLabel GLOB '[0-9][0-9][0-9][0-9]p'
|
||||||
|
OR VersionLabel IN ('4K', '8K', 'SD');
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Nichts zurückzunehmen: die alten Werte waren abgeleitet.</summary>
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,6 +51,31 @@ public class BenennungTests
|
|||||||
public void Bildhoehen_werden_zu_Stufen(int hoehe, string erwartet) =>
|
public void Bildhoehen_werden_zu_Stufen(int hoehe, string erwartet) =>
|
||||||
Assert.That(Benennung.Aufloesung(hoehe), Is.EqualTo(erwartet));
|
Assert.That(Benennung.Aufloesung(hoehe), Is.EqualTo(erwartet));
|
||||||
|
|
||||||
|
/// <summary>Dieselbe Messung als Wort — das, was in der Zeile steht.</summary>
|
||||||
|
[TestCase(3840, 2160, "4K")]
|
||||||
|
[TestCase(1920, 1080, "Full HD")]
|
||||||
|
[TestCase(2560, 1440, "Full HD")]
|
||||||
|
[TestCase(1280, 720, "HD")]
|
||||||
|
[TestCase(1024, 576, "SD")]
|
||||||
|
[TestCase(720, 480, "SD")]
|
||||||
|
[TestCase(null, null, null)]
|
||||||
|
public void Bildgroessen_werden_zu_Woertern(int? breite, int? hoehe, string? erwartet) =>
|
||||||
|
Assert.That(Benennung.Aufloesungswort(breite, hoehe), Is.EqualTo(erwartet));
|
||||||
|
|
||||||
|
/// <summary>Kinoformat: 800 Zeilen, und trotzdem Full HD.</summary>
|
||||||
|
///
|
||||||
|
/// <remarks>
|
||||||
|
/// Derselbe Grund wie eine Stufe höher: gerechnet wird mit Breite und
|
||||||
|
/// Höhe. Nur an der Höhe gemessen hiesse dieser Film „HD", und daneben
|
||||||
|
/// stünde in der Mediathek ein 1280×720 mit demselben Wort.
|
||||||
|
/// </remarks>
|
||||||
|
[Test]
|
||||||
|
public void Ein_beschnittenes_Breitbild_bleibt_Full_HD()
|
||||||
|
{
|
||||||
|
Assert.That(Benennung.Aufloesungswort(1920, 800), Is.EqualTo("Full HD"));
|
||||||
|
Assert.That(Benennung.Aufloesungswort(1280, 720), Is.EqualTo("HD"));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Der Fall aus der Oberfläche, Wort für Wort.</summary>
|
/// <summary>Der Fall aus der Oberfläche, Wort für Wort.</summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void Die_ganze_Tonspur()
|
public void Die_ganze_Tonspur()
|
||||||
@@ -81,7 +106,7 @@ public class BenennungTests
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Die_ganze_Bildspur() =>
|
public void Die_ganze_Bildspur() =>
|
||||||
Assert.That(Benennung.Bildspur("h264", 1040), Is.EqualTo("1080p · H.264"));
|
Assert.That(Benennung.Bildspur("h264", 1040), Is.EqualTo("Full HD · H.264"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Nachtrag: Titel, die nichts hinzufügen.</summary>
|
/// <summary>Nachtrag: Titel, die nichts hinzufügen.</summary>
|
||||||
|
|||||||
@@ -69,14 +69,6 @@ public class FassungTests
|
|||||||
[TestCase("Filme/The Matrix (1999).mkv")]
|
[TestCase("Filme/The Matrix (1999).mkv")]
|
||||||
public void Raet_nicht(string pfad) => Assert.That(FileNames.Fassung(pfad), Is.Null);
|
public void Raet_nicht(string pfad) => Assert.That(FileNames.Fassung(pfad), Is.Null);
|
||||||
|
|
||||||
[TestCase(2160, "4K")]
|
|
||||||
[TestCase(1080, "1080p")]
|
|
||||||
[TestCase(720, "720p")]
|
|
||||||
[TestCase(480, "SD")]
|
|
||||||
[TestCase(null, null)]
|
|
||||||
public void Bildet_die_Fassung_aus_der_Hoehe(int? hoehe, string? erwartet) =>
|
|
||||||
Assert.That(FileNames.FassungAusHoehe(hoehe), Is.EqualTo(erwartet));
|
|
||||||
|
|
||||||
/// <summary>Der Fassungszusatz darf nie im Titel landen.</summary>
|
/// <summary>Der Fassungszusatz darf nie im Titel landen.</summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void Die_Fassung_bleibt_aus_dem_Titel_heraus()
|
public void Die_Fassung_bleibt_aus_dem_Titel_heraus()
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ export type Spur = {
|
|||||||
display: string | null;
|
display: string | null;
|
||||||
/** Die Sprache als Wort — „Deutsch" statt „deu". */
|
/** Die Sprache als Wort — „Deutsch" statt „deu". */
|
||||||
languageName: string | null;
|
languageName: string | null;
|
||||||
|
/** Nur bei Bild: die Auflösung als Wort — „4K", „Full HD", „HD", „SD". */
|
||||||
|
resolutionLabel?: string | null;
|
||||||
|
/** Nur bei Bild: dieselbe Auflösung genau — „1080p". */
|
||||||
|
resolutionExact?: string | null;
|
||||||
};
|
};
|
||||||
export type Datei = {
|
export type Datei = {
|
||||||
id: string; fileName: string; sizeBytes: number;
|
id: string; fileName: string; sizeBytes: number;
|
||||||
|
|||||||
@@ -396,14 +396,20 @@ export function detailseite(art: Art, id: string, zurueck: () => void): HTMLElem
|
|||||||
if (datei.durationSeconds) zeile('Laufzeit', laufzeit(datei.durationSeconds));
|
if (datei.durationSeconds) zeile('Laufzeit', laufzeit(datei.durationSeconds));
|
||||||
|
|
||||||
if (bild) {
|
if (bild) {
|
||||||
// Nur die Stufe, nicht der Codec: „H.264" ist für den, der schauen
|
// **Das Wort, nicht die Zahl.** „Full HD" sagt dem, der schauen will,
|
||||||
// will, kein Unterschied, den er trifft.
|
// ob es sich lohnt; „1080p" ist eine Angabe für den, der eine Stufe
|
||||||
const stufe = bild.display?.split(' · ')[0] ?? null;
|
// einstellt. Beides kommt fertig vom Server — vorher stand hier
|
||||||
|
// `display.split(' · ')[0]`, also die Annahme, dass vor der Auflösung
|
||||||
|
// nie etwas anderes steht.
|
||||||
|
const stufe = bild.resolutionLabel ?? null;
|
||||||
if (stufe) {
|
if (stufe) {
|
||||||
const v = zeile('Auflösung', stufe);
|
const v = zeile('Auflösung', stufe);
|
||||||
// Die gemessene Grösse gehört in den Tooltip: 1920×800 ist kein
|
// Genau und gemessen gehören in den Tooltip: 1920×800 ist kein
|
||||||
// Fehler, sondern Kinoformat.
|
// Fehler, sondern Kinoformat.
|
||||||
if (bild.width && bild.height) v.title = `${bild.width} × ${bild.height}`;
|
v.title = [
|
||||||
|
bild.resolutionExact,
|
||||||
|
bild.width && bild.height ? `${bild.width} × ${bild.height}` : null,
|
||||||
|
].filter(Boolean).join(' · ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user