`MediaItem` und die Typen darunter — die Form, in der die Oberfläche Titel sieht, unabhängig davon, welcher Server sie geliefert hat. Die Namen sind dort geblieben, wo sie ohnehin neutral waren: `title`, `summary`, `year`, `index`. Umbenannt wurde, was Plex-Jargon ist. `ratingKey` heißt `id`, `viewOffset` heißt `resumeMilliseconds`, und aus dem „Großelternteil" ist die Serie geworden, die von Anfang an gemeint war — ein Name, den man in jeder Ansicht im Kopf übersetzen musste. Zwei Dinge, die dabei ehrlicher werden: `isFavourite` gibt es, aber Plex meldet immer `false`. Ein Feld, das ein Server nicht füllt, ist besser als eine Fähigkeit, die es nur auf einem gibt und die sich nirgends setzen ließe. Dateigrößen sind jetzt `Int64`. Ein Remux überschreitet vier Gigabyte mühelos. Die Übersetzung steht in **einer** Datei und geht in **eine** Richtung. Die Drahtmodelle bleiben, wo sie sind — sie tragen Eigenheiten, die nur Plex hat, und die gehören nicht nach oben. Geprüft wird gegen echte Server-Antworten, nicht gegen erfundene Werte: genau dort stehen die Eigenheiten, an denen eine Übersetzung scheitert. Ein Test vergleicht außerdem beide Wege zum Wiedergabe-Profil — sagten sie Unterschiedliches, spielte ein Titel nach dem Umbau plötzlich über einen anderen Player. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
80 lines
3.0 KiB
Swift
80 lines
3.0 KiB
Swift
import Foundation
|
|
import Testing
|
|
import MediaKit
|
|
@testable import PlexKit
|
|
|
|
/// Die Übersetzung der Plex-Modelle in die neutrale Form.
|
|
///
|
|
/// Gegen eine echte Server-Antwort, nicht gegen erfundene Werte: die
|
|
/// Eigenheiten, an denen eine Übersetzung scheitert, stehen genau dort —
|
|
/// „grandparent" für die Serie, Sekunden seit 1970 als Zahl, Fassungen und
|
|
/// Dateien ineinander verschachtelt.
|
|
@Suite("Übersetzung nach MediaKit")
|
|
struct MediaTranslationTests {
|
|
|
|
private func item(_ fixture: String) throws -> PlexItem {
|
|
let url = try #require(Bundle.module.url(forResource: "Fixtures/\(fixture)", withExtension: "json"))
|
|
let container = try PlexResponse.decode(
|
|
PlexMediaContainer<PlexItem>.self,
|
|
from: try Data(contentsOf: url)
|
|
)
|
|
return try #require(container.content.first)
|
|
}
|
|
|
|
@Test("Aus dem Großelternteil wird die Serie")
|
|
func translatesTheGrandparent() throws {
|
|
let episode = try item("episodes-unanalyzed").asMediaItem
|
|
|
|
// Der Name war von Anfang an irreführend: gemeint ist die Serie, und
|
|
// in jeder Ansicht musste man ihn im Kopf übersetzen.
|
|
#expect(episode.kind == .episode)
|
|
#expect(episode.title == "Die erste Folge")
|
|
#expect(episode.seriesTitle == "Eine Serie")
|
|
#expect(episode.index == 1)
|
|
#expect(episode.parentIndex == 1)
|
|
}
|
|
|
|
@Test("Fassungen und Dateien kommen vollständig mit")
|
|
func translatesVersions() throws {
|
|
let movie = try item("movie-with-two-versions").asMediaItem
|
|
|
|
#expect(movie.versions.count == 2)
|
|
#expect(movie.hasMultipleVersions)
|
|
|
|
let first = try #require(movie.versions.first)
|
|
#expect(first.files.isEmpty == false)
|
|
#expect(first.container != nil)
|
|
}
|
|
|
|
@Test("Die Wiedergabe-Entscheidung bekommt dasselbe Profil wie vorher")
|
|
func buildsTheSameProfile() throws {
|
|
// Beide Wege müssen dasselbe sagen — sonst spielte ein Titel nach dem
|
|
// Umbau plötzlich über einen anderen Player.
|
|
let plex = try item("movie-with-two-versions")
|
|
let media = try #require(plex.media.first)
|
|
let part = try #require(media.parts.first)
|
|
|
|
let viaPlex = media.profile(part: part)
|
|
let viaMedia = try #require(plex.asMediaItem.versions.first)
|
|
.profile(file: plex.asMediaItem.versions.first?.files.first)
|
|
|
|
#expect(viaPlex == viaMedia)
|
|
}
|
|
|
|
@Test("Ohne Fortschritt gibt es keinen Balken")
|
|
func leavesUnstartedItemsAlone() throws {
|
|
let movie = try item("movie-with-two-versions").asMediaItem
|
|
|
|
// `watchProgress` ist bewusst `nil` statt 0: ein Balken bei null
|
|
// Prozent sieht aus wie ein Fehler, nicht wie „noch nicht begonnen".
|
|
if movie.resumeMilliseconds == nil || movie.resumeMilliseconds == 0 {
|
|
#expect(movie.watchProgress == nil)
|
|
}
|
|
}
|
|
|
|
@Test("Plex kennt keine Favoriten und behauptet auch keine")
|
|
func doesNotInventFavourites() throws {
|
|
#expect(try item("movie-with-two-versions").asMediaItem.isFavourite == false)
|
|
}
|
|
}
|